diff options
author | Hans Hagen <pragma@wxs.nl> | 2018-01-12 08:12:50 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2018-01-12 08:12:50 +0100 |
commit | d0edf3e90e8922d9c672f24ecdc5d44fe2716f31 (patch) | |
tree | 5b618b87aa5078a8c744c94bbf058d69cd7111b2 /doc/context/sources/general/manuals/metafun | |
parent | 409a95f63883bd3b91699d39645e39a8a761457c (diff) | |
download | context-d0edf3e90e8922d9c672f24ecdc5d44fe2716f31.tar.gz |
2018-01-08 23:11:00
Diffstat (limited to 'doc/context/sources/general/manuals/metafun')
54 files changed, 26656 insertions, 0 deletions
diff --git a/doc/context/sources/general/manuals/metafun/cow-fun.mps b/doc/context/sources/general/manuals/metafun/cow-fun.mps new file mode 100644 index 000000000..4235985ba --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/cow-fun.mps @@ -0,0 +1,154 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%BoundingBox: 52 425 327 625 +%%Comment: originally a CorelDraw cow +%%Creator: MetaPost +%%Pages: 1 +%%EndProlog +%%Page: 1 1 +0 2 dtransform truncate idtransform setlinewidth pop +.625 0 0 setrgbcolor +newpath 245.45 600.34 moveto +242.78 599.40 239.62 596.02 237.67 594.07 curveto +236.74 584.42 244.58 583.63 250.20 577.44 curveto +258.77 573.70 251.21 567.72 256.18 557.42 curveto +257.04 550.94 257.90 543.89 255.31 539.78 curveto +249.48 538.92 247.97 540.22 246.89 531.43 curveto +246.31 526.97 231.77 529.06 229.03 538.27 curveto +227.09 544.97 221.33 546.70 217.80 543.17 curveto +213.77 538.06 215.78 531.22 217.80 527.47 curveto +224.93 517.32 212.04 511.42 205.13 516.74 curveto +199.73 508.68 211.39 500.04 207.43 494.50 curveto +205.78 493.99 204.77 489.17 185.47 500.54 curveto +180.36 504.14 167.83 500.76 168.77 520.63 curveto +168.77 525.82 165.60 543.53 162.14 555.91 curveto +159.41 561.24 156.74 559.08 156.89 553.90 curveto +157.18 547.85 162.94 531.22 155.52 540.22 curveto +153.58 539.21 156.89 523.58 156.89 521.64 curveto +162.00 517.03 157.39 513.58 154.73 512.28 curveto +151.27 518.33 149.62 518.04 147.17 514.44 curveto +141.70 514.08 144.58 528.19 140.26 528.62 curveto +137.02 527.76 139.18 520.06 138.24 518.76 curveto +132.98 524.74 130.90 529.27 127.01 521.64 curveto +126.14 521.64 122.11 519.19 120.96 526.54 curveto +117.65 552.74 107.06 558.36 93.82 565.13 curveto +92.02 565.63 84.24 566.71 79.34 568.15 curveto +73.51 560.88 58.32 565.63 56.23 570.31 curveto +54.79 572.69 54.65 575.21 54.79 576.50 curveto +52.34 580.10 55.87 582.70 59.62 583.06 curveto +62.86 587.16 68.54 594.94 71.28 601.56 curveto +72.29 603.07 74.95 609.34 78.19 609.55 curveto +74.95 612.94 74.30 622.51 82.66 617.33 curveto +87.12 624.02 92.09 624.31 95.76 615.82 curveto +102.89 615.38 102.31 608.69 115.78 605.52 curveto +122.76 602.86 132.77 604.58 140.26 603.72 curveto +136.22 596.88 127.44 566.86 132.98 559.80 curveto +140.76 564.70 141.84 605.38 157.03 595.66 curveto +160.56 593.93 159.91 590.04 164.09 590.18 curveto +170.42 587.45 169.13 600.77 172.51 600.77 curveto +176.47 599.76 183.02 599.04 186.98 599.54 curveto +197.71 600.77 206.93 604.08 223.92 602.50 curveto +231.12 601.78 238.25 601.06 245.45 600.34 curveto +closepath fill +newpath 305.28 560.95 moveto +304.63 560.95 299.95 561.24 299.38 561.24 curveto +302.40 550.44 303.98 536.47 304.20 525.31 curveto +303.70 521.35 299.81 517.46 299.38 525.67 curveto +295.85 530.86 296.42 540.07 293.40 540.29 curveto +287.35 539.64 285.34 513.22 280.01 509.33 curveto +276.26 512.28 280.73 524.02 275.54 524.74 curveto +270.50 524.02 264.31 526.68 266.69 534.46 curveto +270.29 543.02 268.34 554.76 266.54 561.60 curveto +262.37 578.59 264.02 587.09 271.58 596.09 curveto +267.48 604.51 lineto +275.40 608.26 285.62 604.58 290.02 602.21 curveto +294.62 600.26 300.24 595.94 301.10 587.38 curveto +303.34 578.88 304.42 569.74 305.28 560.95 curveto +closepath fill +.625 .625 0 setrgbcolor +newpath 84.38 618.55 moveto +88.34 624.38 92.59 622.94 96.34 615.67 curveto +101.23 615.60 102.46 612.43 104.98 610.78 curveto +122.62 598.39 147.46 607.18 167.90 601.92 curveto +180.94 598.54 190.87 599.76 200.09 602.06 curveto +220.32 607.25 246.10 596.16 263.74 603.86 curveto +274.75 608.62 284.76 605.66 292.97 600.91 curveto +297.58 597.96 299.59 596.09 300.96 591.26 curveto +306.29 572.54 306.29 551.02 309.53 530.57 curveto +309.53 528.84 312.19 526.10 312.48 522.07 curveto +315.79 511.34 316.08 510.12 317.16 502.20 curveto +317.16 501.34 326.52 488.45 325.01 479.02 curveto +323.93 481.25 323.86 482.83 321.62 481.68 curveto +320.33 479.30 320.90 473.90 322.56 471.74 curveto +320.83 470.81 318.46 473.47 317.52 475.20 curveto +318.17 473.04 317.81 470.81 316.73 469.30 curveto +315.86 472.25 316.58 473.18 315.36 473.90 curveto +313.99 472.90 314.21 469.30 314.28 466.20 curveto +313.49 468.07 311.47 472.46 312.55 476.42 curveto +312.48 484.20 308.81 489.10 310.32 499.10 curveto +310.10 504.43 307.30 521.06 304.56 524.30 curveto +303.12 526.25 306.36 510.77 306.36 506.16 curveto +306.65 500.90 307.08 468.72 306.43 463.10 curveto +306.43 459.22 306.22 453.96 307.08 452.16 curveto +308.74 450.79 309.38 450.50 309.60 447.98 curveto +309.24 446.62 308.74 446.04 307.73 445.54 curveto +306.07 444.60 307.37 441.79 306.07 439.85 curveto +304.49 438.77 304.13 441.86 303.34 441.86 curveto +302.69 441.00 303.05 437.98 302.47 436.18 curveto +299.66 433.80 292.18 432.50 289.15 434.66 curveto +289.73 440.64 291.74 441.58 295.63 446.62 curveto +298.66 452.59 297.00 460.94 296.93 468.14 curveto +295.49 480.38 289.22 487.30 289.44 496.44 curveto +287.86 495.72 286.42 494.57 284.26 494.86 curveto +283.39 489.46 286.42 484.56 284.83 480.82 curveto +281.95 471.96 277.06 446.62 279.00 437.76 curveto +280.01 434.74 278.21 433.15 277.06 433.94 curveto +276.77 433.94 276.55 433.94 276.41 433.94 curveto +276.41 433.94 276.55 431.42 275.69 430.92 curveto +274.10 430.34 273.67 431.71 272.66 432.14 curveto +271.22 430.85 272.52 429.48 271.15 428.04 curveto +267.19 428.04 261.36 425.38 257.98 428.26 curveto +257.33 434.16 263.30 436.68 266.47 440.71 curveto +268.63 446.62 271.08 462.89 267.77 474.62 curveto +267.77 475.56 264.38 485.28 261.43 488.66 curveto +258.70 487.66 257.33 485.50 253.22 486.29 curveto +252.58 484.34 253.30 482.33 252.22 480.10 curveto +251.86 479.52 249.34 478.58 249.19 481.39 curveto +248.98 483.05 248.90 486.36 248.26 486.72 curveto +243.65 486.72 233.71 487.08 231.77 493.92 curveto +219.89 492.34 215.93 491.26 206.57 493.42 curveto +196.63 489.67 183.24 506.16 174.53 502.20 curveto +172.51 496.15 173.09 485.64 171.65 481.39 curveto +169.34 474.77 171.14 467.14 171.14 456.41 curveto +170.57 455.40 169.85 454.46 168.48 454.46 curveto +168.48 453.10 169.34 450.86 168.62 449.42 curveto +167.18 447.62 165.89 451.80 165.02 444.60 curveto +163.15 443.74 157.75 442.22 155.59 445.18 curveto +155.88 448.99 158.33 451.30 160.13 453.38 curveto +161.42 456.91 160.99 458.28 160.70 461.81 curveto +160.99 464.98 161.71 468.58 161.86 470.09 curveto +161.86 473.04 162.50 479.30 161.14 481.18 curveto +159.41 482.69 lineto +157.18 487.22 158.33 494.64 157.61 500.26 curveto +155.81 500.69 155.81 500.98 154.01 498.31 curveto +154.01 494.42 153.50 486.36 152.35 483.84 curveto +149.69 479.81 150.84 459.65 151.42 448.56 curveto +151.78 446.47 149.69 447.70 149.76 444.74 curveto +150.05 442.80 147.89 443.59 146.09 444.60 curveto +145.15 445.18 146.59 439.78 145.37 439.56 curveto +142.34 438.84 136.87 438.19 135.22 440.71 curveto +134.57 444.60 137.88 448.06 140.62 451.01 curveto +143.14 455.83 140.90 465.70 140.47 476.28 curveto +138.89 478.22 lineto +134.86 483.19 139.61 496.94 136.51 506.23 curveto +120.02 514.87 122.11 519.19 118.73 537.62 curveto +115.13 557.64 93.38 567.65 79.06 567.65 curveto +73.44 563.04 66.24 563.62 58.54 567.65 curveto +55.66 569.23 54.43 573.19 54.50 576.50 curveto +52.63 580.75 55.22 582.19 59.62 583.49 curveto +62.71 587.81 68.62 594.65 69.19 597.74 curveto +70.34 601.92 75.53 608.11 77.76 609.77 curveto +75.82 613.01 74.81 615.17 77.11 618.55 curveto +79.56 620.14 81.79 616.61 84.38 618.55 curveto +closepath stroke +showpage +%%EOF diff --git a/doc/context/sources/general/manuals/metafun/hacker.png b/doc/context/sources/general/manuals/metafun/hacker.png Binary files differnew file mode 100644 index 000000000..3a54696ee --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/hacker.png diff --git a/doc/context/sources/general/manuals/metafun/m-1.png b/doc/context/sources/general/manuals/metafun/m-1.png Binary files differnew file mode 100644 index 000000000..ab020de9f --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/m-1.png diff --git a/doc/context/sources/general/manuals/metafun/m-2.png b/doc/context/sources/general/manuals/metafun/m-2.png Binary files differnew file mode 100644 index 000000000..512d3eda0 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/m-2.png diff --git a/doc/context/sources/general/manuals/metafun/metafun-backgrounds.tex b/doc/context/sources/general/manuals/metafun/metafun-backgrounds.tex new file mode 100644 index 000000000..200620cae --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-backgrounds.tex @@ -0,0 +1,878 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-backgrounds + +\environment metafun-environment + +\startchapter[reference=sec:page,title={Page backgrounds}] + +\startintro + +Especially in interactive documents, adding backgrounds to the page and text +areas not only enhances readability, but also makes it more convenient to +identify header, footers and navigational areas. In this chapter we will +demonstrate that with \METAPOST\ we can go beyond the \TEX\ based features +present in \CONTEXT. One section is dedicated to graphics and printing, +especially bleeding. + +\stopintro + +\startsection[title={The basic layout}] + +\index {layout} + +In the \CONTEXT\ manual you can find many details on the composition of the page. +When \TEX\ typesets text, crossing the page boundary triggers \TEX's output +routine. This routine is responsible for pasting the body text that goes onto a +page in the correct area. A simple representation of such a page is: + +\startbuffer[a] +\startuseMPgraphic{layout 1} + pickup pencircle scaled 1mm ; + fill unitsquare xyscaled (7cm,8cm) + withcolor .85white ; + fill unitsquare xyscaled (5cm,5cm) shifted (1cm,1.5cm) + withcolor .625yellow ; + fill unitsquare xyscaled (5cm,1cm) shifted (1cm,.5cm) + withcolor .625red ; + fill unitsquare xyscaled (5cm,1cm) shifted (1cm,6.5cm) + withcolor .625red ; + draw unitsquare xyscaled (5cm,7cm) shifted (1cm,.5cm) + withcolor .25white ; + drawarrow (2cm,8cm) -- top (2cm,7.5cm) ; + drawarrow (0cm,7cm) -- lft (1cm,7cm) ; + clip currentpicture to unitsquare xyscaled (7cm,8cm) ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[b] +\startuseMPgraphic{layout 2} + \includeMPgraphic{layout 1} + clip currentpicture to unitsquare scaled 3cm shifted (0,5cm) ; + currentpicture := currentpicture scaled 2 shifted (0,-8cm) ; + setbounds currentpicture to unitsquare xyscaled (6cm,8cm) ; +\stopuseMPgraphic +\stopbuffer + +\getbuffer[a,b] + +\startbuffer[c] +\startlinecorrection[blank] +\hbox + {\useMPgraphic{layout 1}\hskip1cm + \useMPgraphic{layout 2}} +\stoplinecorrection +\stopbuffer + +\getbuffer[c] + +The red areas are the header and footer, while the yellow areas contains the text +flow. We can turn headers on and off and|/|or hide them. For this reason, the +header, text and footer areas together make up the height of the text. + +A close look at the left picture will reveal that the two arrows point to the +center of the lines. This is achieved by the \type {top} and \type {lft} +directives. If we would not have clipped the picture, the arrow would have stuck +half a line width outside the gray area that represents the page. When +constructing such pictures, one should really pay attention to such details, +since it pays off in the overall look and feel of the document. + +The vertical arrow represents the top space, while the horizontal arrow denotes +the distance to the back of the cover (back space). By changing their values, you +can shift the main body text on the page. In a double sided layout scheme, the +back space is automatically mirrored on even pages. + +An advanced \METAPOST\ user may wonder why we hard code the dimensions, and avoid +\METAPOST's powerful mechanisms for defining relations. Our experience has taught +us that in pictures like this, providing a general solution seldom pays large +dividents or savings in time. + +\typebuffer[a] + +As you can see, the left graphic is defined as a series of rectangles. The \type +{xyscaled} macro is part of the \CONTEXT\ files, and saves some typing and space. +It is defined as a primary, requiring both left and right operands. + +\starttyping +primarydef p xyscaled q = + p xscaled (xpart q) yscaled (ypart q) +enddef ; +\stoptyping + +Zooming in on the top left corner only takes a few lines. First we clip the +correct part, next we scale it up, and finally we let the bounding box suit the +left picture. + +\typebuffer[b] + +This code demonstrates how you can reuse a graphic inside another one. This +strategy can easily be used to stepwise build (or extend) graphics. The two +graphics were put side by side with the following command. Watch the use of line +correction commands. They optimize the white space around the graphic. + +\typebuffer[c] + +As soon as you want to make an electronic document, you will want to use +different areas of the screen for different purposes: text, menus, buttons, etc. +For this reason, \CONTEXT\ provides not only left and right margins, but also +additional left and right edge areas and top and bottom margins. These areas are +shown in the figure on the next page. + +\startbuffer[aa] +pickup pencircle scaled 2pt ; + +numeric w[], h[], x[], y[], u ; u := .5cm ; + +numeric width ; width := \the\textwidth ; +numeric height ; height := \the\textheight ; +\stopbuffer + +\startbuffer[bb] +w[1] = 2u ; w[2] = 3u ; w[4] = 3u ; w[5] = 2u ; +h[1] = 1u ; h[2] = 1u ; h[4] = 1u ; h[5] = 1u ; + +w[1]+w[2]+w[3]+w[4]+w[5]+4u = width ; +h[1]+h[2]+h[3]+h[4]+h[5]+4u = height ; + +x[1] = 1u ; y[1] = 1u ; +x[2] = x[1] + w[1] + .5u ; y[2] = y[1] + h[1] + .5u ; +x[3] = x[2] + w[2] + .5u ; y[3] = y[2] + h[2] + .5u ; +x[4] = x[3] + w[3] + .5u ; y[4] = y[3] + h[3] + .5u ; +x[5] = x[4] + w[4] + .5u ; y[5] = y[4] + h[4] + .5u ; +\stopbuffer + +\startbuffer[cc] +def do_it (expr xx, yy, cc) = + draw unitsquare + xyscaled (w[xx],h[yy]) shifted (x[xx],y[yy]) + withcolor if cc : .625red else : .625yellow fi ; +enddef ; + +fill unitsquare xyscaled (width,height) withcolor .85white; + +do_it (1,1,false) ; do_it (5,1,false) ; +do_it (2,1,false) ; do_it (3,1,false) ; do_it (4,1,false) ; + +do_it (1,2,false) ; do_it (5,2,false) ; +do_it (2,2,true ) ; do_it (3,2,true ) ; do_it (4,2,true ) ; + +do_it (1,3,false) ; do_it (5,3,false) ; +do_it (2,3,true ) ; do_it (3,3,true ) ; do_it (4,3,true ) ; + +do_it (1,4,false) ; do_it (5,4,false) ; +do_it (2,4,true ) ; do_it (3,4,true ) ; do_it (4,4,true ) ; + +do_it (1,5,false) ; do_it (5,5,false) ; +do_it (2,5,false) ; do_it (3,5,false) ; do_it (4,5,false) ; +\stopbuffer + +\startbuffer[dd] +def do_it (expr yy, tt) = + path p ; + p := unitsquare xyscaled (w[1],h[yy]) shifted (x[1],y[yy]) ; + label.lft(tt, center p shifted (-w[1]/2-u-.25cm,0)) ; +enddef ; + +do_it (1,btex bottom etex) ; +do_it (2,btex footer etex) ; +do_it (3,btex text etex) ; +do_it (4,btex header etex) ; +do_it (5,btex top etex) ; +\stopbuffer + +\startbuffer[ee] +def do_it (expr xx, tt) = + path p ; + p := unitsquare xyscaled (w[xx],h[1]) shifted (x[xx],y[1]) ; + label(tt, center p shifted (0,height-h[1]/2)) ; +enddef ; + +do_it (1,btex edge etex) ; +do_it (2,btex margin etex) ; +do_it (3,btex text etex) ; +do_it (4,btex margin etex) ; +do_it (5,btex edge etex) ; +\stopbuffer + +\startbuffer[ff] +setbounds currentpicture to + unitsquare xyscaled (width,height) ; +\stopbuffer + +% We use two chars for buffer names, otherwise we can get +% get in conflict with the next buffers with similar names. + +\startpostponing +\centerbox{\processMPbuffer[aa,bb,cc,dd,ee,ff]} +\stoppostponing + +When defining this graphic, all areas have related dimensions. Here it makes +sense to let \METAPOST\ calculate these dimensions as much as possible. First we +define the five by five matrix of areas. We pass the width and height of the main +text area. Because they are stored in \TEX\ dimension registers, we have to +prefix them by \type {\the}. + +\typebuffer[aa] + +We now specify the lower left corners using \type {=} instead of the \type {:=}, +which means that \METAPOST\ will calculate \type {w[3]} and \type {h[3]} for us. + +\typebuffer[bb] + +Because we are going to repeat ourselves, we draw the areas using a macro. +Depending on its importance, we color it red or yellow. + +\typebuffer[cc] + +This picture in itself is not yet explanatory, so we add some labels. Again, we +use a macro, which we feed with a picture generated by \TEX. Since these pictures +are filtered from the source and pre||processed, we cannot embed the \type +{btex}||\type {etex} in the macro \type {do_it} and pass a string. It has to be +done this way. \footnote {This is true only in a regular \METAPOST\ run. In +\CONTEXT\ \MKIV\ we follow a different route.} + +\typebuffer[dd] + +In the horizontal direction we have edges, margins and text. There are left and +right edges and margins, which are swapped on even pages when you typeset a +double sided document. + +\typebuffer[ee] + +Since we want the graphic to match the dimensions of the text area of the current +page, we have to make sure that the bounding box is adapted accordingly. By this +action, the labels will fall outside the bounding box. When we directly embed a +graphic, this works ok, but when we start scaling and reusing, due to the object +reuse mechanism the graphic will be clipped to the bounding box. + +\typebuffer[ff] + +In the following sections we will demonstrate how you can put graphics behind +these 25~areas, as well as behind the (left and right) page. + +\stopsection + +\startsection[title={Setting up backgrounds}] + +\index {overlays} +\index {backgrounds} + +One way of protecting a document for unwanted usage is to put an annoying word in +the background. If you like this, you may try the following. The macro \type +{ysized} is part of the macros that come with \CONTEXT\ and scales a picture to a +specific size. + +\startbuffer[a] +\startuniqueMPgraphic{concept} + draw btex \colored[s=.8]{\bf CONCEPT} etex rotated 60 ; + currentpicture := currentpicture + ysized (\overlayheight-.5cm) ; +\stopuniqueMPgraphic + +\defineoverlay[concept][\uniqueMPgraphic{concept}] +\stopbuffer + +\typebuffer[a] + +You can now put this graphic in the page background by +saying: + +\starttyping +\setupbackgrounds[page][background=concept] +\stoptyping + +You may consider the next alternative a bit better, but still it renders the text +unreadable. Like \type {xysized}, the macro \type {enlarged} is not part of +standard \METAPOST, but comes with \CONTEXT. + +\startbuffer[b] +\startuniqueMPgraphic{copyright} + picture p ; p := btex \colored[s=.8]{COPYRIGHT} etex + rotated 90 ; + setbounds p to boundingbox p enlarged 1pt ; + draw p ; + currentpicture := currentpicture + xysized (\overlaywidth,\overlayheight) ; +\stopuniqueMPgraphic + +\defineoverlay[copyright][\uniqueMPgraphic{copyright}] +\stopbuffer + +\typebuffer[b] + +Again, we put this graphic in the background. By using a unique graphic, we make +sure that it's rendered only once and reused when possible. + +\startbuffer[c] +\setupbackgrounds[text][rightmargin][background=copyright] +\stopbuffer + +\typebuffer[c] + +\doifnotmode{screen}{\getbuffer[b,c]} + +In both cases, we slightly scale down the graphic. We do so because otherwise a +small portion of the text is clipped off. This is unrelated to \TEX\ or +\METAPOST, but a characteristic of the font. Compare the following Pagella, Latin +Modern and Termes gi's (the Pagella is the body font of this text). + +\startbuffer +\hbox \bgroup + \hbox{\definedfont[file:texgyrepagella-regular at 6cm]gi}% + \hbox{\definedfont[file:lmroman10-regular at 6cm]gi}% + \hbox{\definedfont[file:texgyretermes-regular at 6cm]gi}% +\egroup +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +{\showboxes \getbuffer} +\stoplinecorrection + +Watch how the bounding boxes differ and sometimes cross the shape. So, in order +not to loose part of a glyph when clipping, you need to add a bit of space. \in +{Figure} [fig:annoying] shows the two backgrounds in action. + +\startbuffer +\getbuffer[a,b] +\def\ShowPage#1% % (yet) no image as background to image + {\framed % possible due to nested file problems + [background=#1,offset=overlay] + {\typesetfile[mfun-900.tex][page=1,width=.4\textwidth]}} +\startcombination + {\ShowPage{concept}} {concept} + {\ShowPage{copyright}} {copyright} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:annoying] + {Two examples of annoying backgrounds.} + {\getbuffer} + +If you really want to add such texts to a document, in \CONTEXT\ we don't have to +use the page background, but can use one of the layout areas instead (like \type +{[text][text]} or \type {[text][leftmargin]}) + +\typebuffer[d] + +There is one drawback: when your left and right margin have different dimensions, +the text will be scaled differently on odd and even pages. Normally this is no +problem for a draft. + +As an alternative you can use the \type {\setuptexts} command and wrap the +graphic in a box with the right dimensions, using code like: + +\starttyping +\startuniqueMPgraphic{copyright} + picture p ; p := btex COPYRIGHT etex rotated 90 ; + setbounds p to boundingbox p enlarged 1pt ; + draw p withcolor .8white ; + xyscale_currentpicture(\the\leftmarginwidth,\the\textheight) ; +\stopuniqueMPgraphic + +\setuptexttexts [margin] [] [\uniqueMPgraphic{copyright}] +\stoptyping + +The graphic goes into the outer margin. The second argument can be used to put +something in the inner margin. + +\stopsection + +\startsection[title={Multiple overlays}] + +\index{overlays+stack} + +\setupbackgrounds[text][rightmargin][background=] + +You can stack overlays. Consider the next case, where we assume that you have +enabled interaction support using \type {\setupinteraction[state=start]}: + +\starttyping +\setupbackgrounds + [page] + [background={color,nextpage}, + backgroundcolor=darkyellow] +\stoptyping + +Here, the page gets a colored background and a hyperlink to the next page, +previously defined by: + +\starttyping +\defineoverlay[nextpage][\overlaybutton{nextpage}] +\stoptyping + +An \type {\overlaybutton} is just a button, with all attributes (color, frame, +etc) set to nothing, having the dimensions of the overlay. The argument is one of +the permitted destinations, like \type {nextpage}, \type {firstpage}, \type +{SearchDocument} and alike. + +For efficiency reasons, the background areas (like \type {[text][text]}) are +calculated only when their definition has changed. When a background changes per +page, we have to recalculate it on each page. In the next example, the macro +\type {\overlaybutton} generates a different button on each page. But, since we +don't explicitly set the background at each page, there is no way the background +drawing mechanism can know that this button has changed. Therefore, we must force +recalculation with: + +\starttyping +\setupbackgrounds[state=repeat] +\stoptyping + +You can test this concept yourself with the following code. Here we assume that +you have a file called \type {tufte.tex} on your system, which is the case if you +have \CONTEXT\ installed. However, you can just as easily use any file having a +paragraph of two of text. + +\starttyping +\starttext +\setupinteraction[state=start] +\setupbackgrounds[state=repeat] +\defineoverlay[nextpage][\overlaybutton{nextpage}] +\setupbackgrounds[text][text][background=nextpage] +\dorecurse{20}{\input tufte \par} +\stoptext +\stoptyping + +Note that you can move forward from page to page in the resulting \PDF\ file by +clicking on each page with the mouse. Now compile this file without setting the +background state to \type {repeat} and note the difference as you click pages +with the mouse. + +Setting the state was not needed when we used the page background: + +\starttyping +\setupbackgrounds[page][background=nextpage] +\stoptyping + +The \type {\dorecurse} macro is handy for testing since it saves us typing. One +can nest this macro as in: + +\starttyping +\dorecurse{20}{\dorecurse{10}{Hello World! }\par} +\stoptyping + +The current step is available in \type {\recurselevel} and the depth (nesting +level) in \type {\recursedepth}. + +\stopsection + +\startsection[title={Crossing borders}] + +\index{backgrounds} + +In many cases, the previously mentioned background areas will suffice, but in the +case of more complicated backgrounds, you may wish to use \METAPOST\ to draw +graphics that combine or span these areas. + +At runtime \CONTEXT\ saves information on the layout that can be picked up by +\METAPOST. The framework for a page graphic is: + +\starttyping +StartPage; + % all kind of commands +StopPage ; +\stoptyping + +Between the \type {StartPage} and \type {StopPage} command you have access to a +wide range of variables: + +\starttabulate[|l|Tp|] +\HL +\NC page \NC PaperHeight PaperWidth \NC \NR +\NC \NC PrintPaperHeight PrintPaperWidth \NC \NR +\NC \NC PageOffset PageDepth \NC \NR +\NC margins \NC TopSpace BackSpace \NC \NR +\NC text \NC MakeupHeight MakeupWidth \NC \NR +\NC vertical \NC TopHeight TopDistance \NC \NR +\NC \NC HeaderHeight HeaderDistance \NC \NR +\NC \NC TextHeight \NC \NR +\NC \NC FooterDistance FooterHeight \NC \NR +\NC \NC BottomDistance BottomHeight \NC \NR +\NC horizontal \NC LeftEdgeWidth LeftEdgeDistance \NC \NR +\NC \NC LeftMarginWidth LeftMarginDistance \NC \NR +\NC \NC TextWidth \NC \NR +\NC \NC RightMarginDistance RightMarginWidth \NC \NR +\NC \NC RightEdgeDistance RightEdgeWidth \NC \NR +\HL +\stoptabulate + +Since using these variables to construct paths is not that handy because the +areas are available as predefined paths, which we will demonstrate here. + +\placefigure + [here][fig:back 1] + {A background with combined areas.} + {\startcombination + {\typesetfile[mfun-900.tex][page=2,width=.4\textwidth]}{even} + {\typesetfile[mfun-900.tex][page=3,width=.4\textwidth]}{odd} + \stopcombination} + +In \in {figure} [fig:back 1] you see two pages (odd and even) with a background +spanning the outer margin and the text area. You can access an area in two ways. +The area itself is available as \type {Area}. + +\starttyping +StartPage ; + fill Area[Text][Text] withcolor .85white ; +StopPage ; +\stoptyping + +If you use an area this way, you will notice that it is not positioned at the +right place. An \type {Area} is just a rectangle. If you want a positioned area, +you should use the \type {Field} array: + +\starttyping +StartPage ; + fill Field[Text][Text] withcolor .85white ; +StopPage ; +\stoptyping + +The location of an area is available in \type {Location}, so the previous +definition is the same as: + +\starttyping +StartPage ; + fill Area[Text][Text] shifted Location[Text][Text] + withcolor .85white ; +StopPage ; +\stoptyping + +The following definition fills and draws the margin and text areas. + +\typebuffer[back-2] + +This background is assigned to the page layer by saying: + +\typebuffer[back-0] + +As you can see in \in {figure} [fig:back 2], the text is typeset rather tightly +between the left and right margins. + +\placefigure + [here][fig:back 2] + {A background with split areas.} + {\startcombination + {\typesetfile[mfun-900.tex][page=4,width=.4\textwidth]}{even} + {\typesetfile[mfun-900.tex][page=5,width=.4\textwidth]}{odd} + \stopcombination} + +This can easily be solved by enlarging the areas a bit. The next example +demonstrates this on the text area, which is shown in \in {figure} [fig:back 3]. + +\typebuffer[back-3] + +\placefigure + [here][fig:back 3] + {A background with enlarged text area.} + {\startcombination + {\typesetfile[mfun-900.tex][page=6,width=.4\textwidth]}{even} + {\typesetfile[mfun-900.tex][page=7,width=.4\textwidth]}{odd} + \stopcombination} + +The \type {enlarged} macro can be used like \type {shifted} and accepts either a +numeric or a pair. + +How do we define a background as in \in {figure} [fig:back 1]? Because \type +{Field} provides us the positioned areas, we can use the corners of those. + +\typebuffer[back-1] + +In this definition we calculate a different path for odd and even pages. When +done, we enlarge the path a bit. If you want to use different offsets in all +directions, you can use moved corner points. + +\typebuffer[back-4] + +Here we displace the corners randomly which leads to backgrounds like \in +{figure} [fig:back 4]. The following definition would have worked as well: + +\typebuffer[back-4x] + +\placefigure + [here][fig:back 4] + {A random text area.} + {\startcombination + {\typesetfile[mfun-900.tex][page=8,width=.4\textwidth]}{even} + {\typesetfile[mfun-900.tex][page=9,width=.4\textwidth]}{odd} + \stopcombination} + +The previous graphics are defined as usable ones, which means that they will be +recalculated each page. This is rather inefficient when the shapes don't change. +But, using a reusable graphic instead, would result in only one graphic for both +pages. Since the layout for the left and right page differs, another method is +needed. + +Instead of putting the same graphic on the page layer, we put two different ones +on the left and right page layer. + +\starttyping +\defineoverlay[left page] [\useMPgraphic{left page}] +\defineoverlay[right page][\useMPgraphic{right page}] + +\setupbackgrounds[leftpage] [background=left page] +\setupbackgrounds[rightpage][background=right page] +\stoptyping + +Now we only have to split the previously defined graphic into two parts. In order +to force consistency, we isolate the code that fills and draws. The left page +code looks like: + +\starttyping +\startreusableMPgraphic{left page} + StartPage ; + path Main ; Main := + llcorner Field[OuterMargin][Text] -- + lrcorner Field[Text] [Text] -- + urcorner Field[Text] [Text] -- + ulcorner Field[OuterMargin][Text] -- cycle ; + \includeMPgraphic{draw page} + StopPage ; +\stopreusableMPgraphic +\stoptyping + +The right page text looks similar: + +\starttyping +\startreusableMPgraphic{right page} + StartPage ; + path Main ; Main := + lrcorner Field[OuterMargin][Text] -- + llcorner Field[Text] [Text] -- + ulcorner Field[Text] [Text] -- + urcorner Field[OuterMargin][Text] -- cycle ; + \includeMPgraphic{draw page} + StopPage ; +\stopreusableMPgraphic +\stoptyping + +Watch how we used a reusable graphic first and a simple usable one next. +Actually, the next graphic is not a stand alone graphic. + +\starttyping +\startuseMPgraphic{draw page} + Main := Main enlarged 6pt ; + pickup pencircle scaled 2pt ; + fill Page withcolor .625white ; + fill Main withcolor .850white ; + draw Main withcolor .625red ; +\stopuseMPgraphic +\stoptyping + +We have seen some predefined paths and locations. Apart from the \type {Page} +path, they take two arguments that specify their position on the layout grid. + +\starttabulate[|lT|l|] +\HL +\NC path Area [][] \NC an area similar to a \CONTEXT\ one \NC \NR +\NC pair Location [][] \NC the position of this area \NC \NR +\NC path Field [][] \NC the area positioned at the right place \NC \NR +\NC path Page \NC the page itself \NC \NR +\HL +\stoptabulate + +Some less used and more obscure variables are the following. + +\starttabulate[|lT|l|] +\HL +\NC numeric Hstep [] \NC the horizontal distance to the previous area \NC \NR +\NC numeric Vstep [] \NC the vertical distance to the previous area \NC \NR +\NC numeric Hsize [] \NC the width of an area \NC \NR +\NC numeric Vsize [] \NC the height of an area \NC \NR +\HL +\stoptabulate + +The array variables are accessed by using constants: + +\starttabulate[|l|l|] +\HL +\NC horizontal \NC vertical \NC \NR +\HL +\NC LeftEdge \NC Top \NC \NR +\NC LeftEdgeSeparator \NC TopSeparator \NC \NR +\NC LeftMargin \NC Header \NC \NR +\NC LeftMarginSeparator \NC HeaderSeparator \NC \NR +\NC Text \NC Text \NC \NR +\NC RightMarginSeparator \NC FooterSeparator \NC \NR +\NC RightMargin \NC Footer \NC \NR +\NC RightEdgeSeparator \NC BottomSeparator \NC \NR +\NC RightEdge \NC Bottom \NC \NR +\HL +\stoptabulate + +In addition to these, there are \type {Margin}, \type {InnerMargin} and \type +{OuterMargin} which adapt themselves to the current odd or even page. The same is +true for \type {Edge}, \type {InnerEdge} and \type {OuterEdge}, although these +will seldom be used, since interactive documents are always single sided. + +We started this chapter with spending a lot of code to simulate the page areas. +It will be clear now that in practice this is much easier using the mechanism +described here. + +\placefigure + [here][fig:back 5] + {A quick way to draw all used areas.} + {\setupexternalfigures[background=color,backgroundcolor=white]% + \startcombination + {\typesetfile[mfun-900.tex][page=10,width=.4\textwidth]}{even} + {\typesetfile[mfun-900.tex][page=11,width=.4\textwidth]}{odd} + \stopcombination} + +In \in {figure} [fig:back 5] we see all used areas. Areas that are not used are +not drawn (which saves some testing). This background was defined as: + +\typebuffer[back-5] + +We use two nested \type {for} loops to step over the areas. A \type {for} loop +with a step of~1 will fail, because the indices are defined in a rather special +way. On the other hand, the mechanism is rather tolerant, in the sense that \type +{[i][j]} and \type {[j][i]} are both accepted. + +\stopsection + +\startsection[title={Bleeding}] + +\index {bleeding} + +If you want to share your document all over the world, it makes sense to use a +paper format like {\em letter} or {\em A4}. In that case, the layout often +matches the paper size. + +\startlinecorrection[blank] +\startMPcode + path p ; p := fullcircle xyscaled (21mm,29.7mm) ; + path q ; q := boundingbox p ; + fill q withcolor .625white ; + fill p withcolor .625yellow ; + currentpicture := currentpicture shifted (-31mm,0) ; + fill q withcolor .625white ; + fill p xsized (bbwidth(p)-2mm) withcolor .625yellow ; + currentpicture := currentpicture shifted (-31mm,0) ; + fill q withcolor .625white ; + fill p withcolor .625yellow ; + draw q enlarged -1mm withpen pencircle scaled 2mm withcolor .625white ; +\stopMPcode +\stoplinecorrection + +The left picture demonstrates what happens when you have a printer that is +capable of printing from edge to edge. If you have such a printer, you're lucky. +The middle picture demonstrates what happens if you have a properly set up +printing program and|/|or printer: the page is scaled down so that the content +fits into the non printable area of the printer. One reason why printers don't +print from edge to edge is that the engine is not that happy when toner or ink +ends up next to the page. The third picture shows what happens when a printer +simply ignores content that runs over the non printable area. In many cases it's +best to make sure that the content leaves a margin of 5mm from the edges. + +Books and magazines seldom use the popular desk||top paper sizes. Here the +designer determined the paper size and layout more or less independent from the +size of the sheet on which the result is printed. Instead of one page per sheet, +arrangements of 2 upto 32 or more pages per sheet are made. The process of +arranging pages in such a way that these sheets can be folded and combined into +books is called page imposition. \CONTEXT\ supports a wide range of page +imposition schemes. More information on this can be found in the \CONTEXT\ +manuals. + +The fact that the sheet on which a page is printed is larger than the page itself +opens the possibility to use the full page for content. In that case, especially +when you use background graphics, you need to make sure that indeed the page is +covered completely. Where in desk top printing you can get away with imperfection +simply because the printing engines have their limitations, in professional +output you need to be more considerate. + +\startlinecorrection[blank] +\startMPcode + path p ; p := fullsquare xyscaled (4cm,5cm) ; + path q ; q := fullsquare xyscaled (3cm,4cm) ; + path r ; r := fullsquare xyscaled (2cm,3cm) shifted (-.5cm,.5cm) ; + fill p withcolor .625white ; + fill q withcolor .850white ; + currentpicture := currentpicture shifted (-45mm,0) ; + fill p withcolor .625white ; + fill q withcolor .850white ; + fill r withcolor transparent(1,.5,.625yellow) ; + currentpicture := currentpicture shifted (-45mm,0) ; + fill p withcolor .625white ; + fill q withcolor .850white ; + r := r topenlarged 2mm leftenlarged 2mm ; + fill r withcolor transparent(1,.5,.625yellow) ; +\stopMPcode +\stoplinecorrection + +Slightly enlarging a graphic so that it exceeds the natural page limits is called +bleeding. Because quite often layout elements have a rectangular nature, +\METAFUN\ provides a couple of operations that can save you some work in defining +bleeding boxes. + +\startbuffer +path p, q ; +def ShowPath = + fill p withcolor transparent(1,.5,.625yellow) ; + fill q withcolor transparent(1,.5,.625yellow) ; + currentpicture := currentpicture shifted (-25mm,0) ; +enddef ; +p := q := fullsquare xyscaled (2cm,3cm) ; ShowPath ; +p := p leftenlarged 2mm ; ShowPath ; +p := p topenlarged 2mm ; ShowPath ; +p := p rightenlarged 2mm ; ShowPath ; +p := p bottomenlarged 2mm ; ShowPath ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This graphic is generated as follows: + +\typebuffer + +The trick is in the last couple of lines. In addition to the general \type +{enlarged} operator, we have 4~operators that enlarge a rectangle in a certain +direction. This means that we can define the original path using dimensions +related to the layout, and add bleed strips independently. + +\startbuffer +path p ; p := fullsquare xyscaled (4cm,1cm) ; +path q ; q := p leftenlarged 2mm topenlarged 2mm ; +fill p withcolor transparent(1,.5,.625yellow) ; +fill q withcolor transparent(1,.5,.625yellow) ; +draw boundingbox currentpicture withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This example demonstrates that when we enlarge a graphic, the bounding box also +gets larger. Because this can interfere with the placement of such a graphic, we +need to make sure that the bleeding is there but not seen. + +\startbuffer +path p ; p := fullsquare xyscaled (4cm,1cm) ; +path q ; q := p leftenlarged 2mm topenlarged 2mm ; +fill p withcolor transparent(1,.5,.625yellow) ; +fill q withcolor transparent(1,.5,.625yellow) ; +setbounds currentpicture to p ; +draw boundingbox currentpicture withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +There are two more operators: \type {innerenlarged} and \type {outerenlarged}. +These expand to either \type {leftenlarged} or \type {rightenlarged}, depending +on the page being left or right hand. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-backpage.tex b/doc/context/sources/general/manuals/metafun/metafun-backpage.tex new file mode 100644 index 000000000..82931d756 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-backpage.tex @@ -0,0 +1,53 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\doifmode{book}{\endinput} + +\startcomponent metafun-backpage + +\environment metafun-environment + +\startstandardmakeup[doublesided=no,page=right] + % back page +\stopstandardmakeup + +\setupbackgrounds + [leftpage] + [background=back page] + +\definecolor[twhite][s=1,t=.80,a=1] + +\setupbackgrounds + [text][text] + [background=color, + backgroundcolor=twhite, + backgroundoffset=.5cm] + +\setuplayout + [cutspace=2cm, + backspace=8cm, + header=0pt, + footer=0pt, + topspace=17cm, + bottomspace=2cm] + +\startstandardmakeup[doublesided=no,page=left,top=,bottom=] + + \switchtobodyfont[big] + + \setupinterlinespace[stretch=.5] + + \getbuffer[backtext] + + \blank + + \getbuffer[backbanner] + +\stopstandardmakeup + +\setupbackgrounds + [rightpage] + [background=] + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-basics.tex b/doc/context/sources/general/manuals/metafun/metafun-basics.tex new file mode 100644 index 000000000..df556e239 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-basics.tex @@ -0,0 +1,3587 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-basics + +\environment metafun-environment + +\startchapter[title={A few more details}] + +\startintro + +In this chapter we will see how to define a \METAPOST\ graphic, and how to +include it in a document. Since the exact dimensions of graphics play an +important role in the placement of a graphic, we will explore the way a bounding +box is constructed. + +We will also pay attention to the usage of units and the side effects of scaling +and shifting, since they can contradict our expectations in unexpected ways. +Furthermore we will explore a few obscure areas. + +\stopintro + +\startsection[title={Making graphics}] + +\index{graphics} + +In this manual we will use \METAPOST\ in a rather straightforward way, and we +will try to avoid complicated math as much as possible. We will do a bit of +drawing, clipping, and moving around. Occasionally we will see some more +complicated manipulations. + +When defined as stand||alone graphic, a \METAPOST\ file looks like this: + +\starttyping +% Let's draw a circle. + +beginfig (7) ; + draw fullcircle scaled 3cm withpen pencircle scaled 1cm ; +endfig ; + +end . +\stoptyping + +The main structuring components in such a file are the \type {beginfig} and \type +{endfig} macros. Like in a big story, the file has many sub||sentences, where +each sub||sentence ends with a semi||colon. Although the \type {end} command at +the end of the file concludes the story, putting a period there is a finishing +touch. Actually, after the \type {end} command you can put whatever text you +wish, your comments, your grocery list, whatever. Comments in \METAPOST, prefixed +by a percent sign, as in \typ {% Let's draw a circle}, are ignored by the +interpreter, but useful reminders for the programmer. + +If the file is saved as \type {yourfile.mp}, then the file is processed by +\METAPOST\ by issuing the following command: + +\starttyping +mpost yourfile +\stoptyping + +after which you will have a graphic called \type {yourfile.7}, which contains a +series of \POSTSCRIPT\ commands. Because \METAPOST\ does all the work, this file +is efficient and compact. The number of distinct \POSTSCRIPT\ operators used is +limited, which has the advantage that we can postprocess this file rather easily. +Alternatively \METAPOST\ can generate \SVG\ output. It does when you say + +\starttyping +outputformat := "svg" ; +\stoptyping + +Here we will not go into details about this format. Even \POSTSCRIPT\ is not +covered in detail as we use \METAPOST\ mostly in embedded form. + +We can view this file in a \POSTSCRIPT\ viewer like \GHOSTVIEW\ or convert the +graphic to \PDF\ (using \type {mptopdf}) and view the result in a suitable \PDF\ +viewer like \ACROBAT. Of course, you can embed such a file in a \CONTEXT\ +document, using a command like: + +\starttyping +\externalfigure[yourfile.7] +\stoptyping + +We will go in more detail about embedding graphics in \in {chapter} +[sec:embedding]. + +If you have installed \CONTEXT, somewhere on your system there resides a file +\type {mp-tool.mp}. If you make a stand||alone graphic, it's best to put the +following line at the top of your file: + +\starttyping +input mp-tool ; % or input metafun ; +\stoptyping + +By loading this file, the resulting graphic will provide a high resolution +bounding box, which enables more accurate placement. The file also sets the \typ +{prologues := 1} so that viewers like \GHOSTVIEW\ can refresh the file when it is +changed. + +Next we will introduce some more \METAPOST\ commands. From now on, we will omit +the encapsulating \type {beginfig} and \type {endfig} macros. If you want to +process these examples yourself, you should add those commands yourself, or if +you use \CONTEXT\ you don't need them at all. + +\startbuffer +pickup pencircle scaled .5cm ; +draw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ; +draw origin withcolor .625yellow ; +pickup pencircle scaled 1pt ; +draw bbox currentpicture withcolor .625red ; +\stopbuffer + +\typebuffer + +In this example we see a mixture of so called primitives as well as macros. A +primitive is something hard coded, a built||in command, while a macro is a +collection of such primitives, packaged in a way that they can be recalled +easily. Where \type {scaled} is a primitive and \type {draw} a macro, \type +{unitsquare} is a path variable, an abbreviation for: + +\starttyping +unitsquare = (0,0) -- (1,0) -- (1,1) -- (0,1) -- cycle ; +\stoptyping + +The double dash (\type {--}) is also a macro, used to connect two points with a +straight line segment. However, \type {cycle} is a primitive, which connects the +last point of the unitsquare to the first on unitsquare's path. Path variables +must first be declared, as in: + +\starttyping +path unitsquare ; +\stoptyping + +A large collection of such macros is available when you launch \METAPOST. Consult +the \METAPOST\ manual for details. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +In the first line of our example, we set the drawing pen to \type {.5cm}. You can +also specify such a dimension in other units, like points (\type {pt}). When no +unit is provided, \METAPOST\ will use a big point (\type {bp}) , the \POSTSCRIPT\ +approximation of a point. + +The second line does just as it says: it draws a rectangle of certain dimensions +in a certain color. In the third line we draw a colored dot at the origin of the +coordinate system in which we are drawing. Finally, we set up a smaller pen and +draw the bounding box of the current picture, using the variable \type +{currentpicture}. Normally, all drawn shapes end up in this picture variable. + +\stopsection + +\startsection[title={Bounding boxes}] + +\index{boundingbox} + +If you take a close look at the last picture in the previous section, you will +notice that the bounding box is larger than the picture. This is one of the nasty +side effects of \METAPOST's \type {bbox} macro. This macro draws a box, but with +a certain offset. The next example shows how we can manipulate this offset. +Personally I never use the \type {bbox} macro because this offset is rather +annoying. Also, the \type {boundingbox} operator combined with \type {enlarged} +can provide any offset you want. + +\startbuffer +pickup pencircle scaled .5cm ; +draw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ; +path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ; +draw bb withpen pencircle scaled 1pt withcolor .625red ; +draw origin withpen pencircle scaled 5pt withcolor .625yellow ; +\stopbuffer + +\typebuffer + +In the third line we define a path variable. We assign the current bounding box +to this variable, but first we set the offset to zero. The last line demonstrates +how to draw such a path. Instead of setting the pen as we did in the first line, +we pass the dimensions directly. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Where \type {draw} draws a path, the \type {fill} macro fills one. In order to be +filled, a path should be closed, which is accomplished by the \type {cycle} +primitive, as we saw in constructing the \type {unitsquare} path. + +\startbuffer +pickup pencircle scaled .5cm ; +fill unitsquare xscaled 8cm yscaled 1cm withcolor .625white ; +path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ; +draw bb withpen pencircle scaled 1pt withcolor .625red ; +draw origin withpen pencircle scaled 5pt withcolor .625yellow ; +\stopbuffer + +\typebuffer + +This example demonstrates that when we fill the path, the resulting graphic is +smaller. Where \type {draw} follows the center of a path, \type {fill} stays +inside the path. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +A third alternative is the \type {filldraw} macro. From the previous examples, we +would expect a bounding box that matches the one of the drawn path. + +\startbuffer +pickup pencircle scaled .5cm ; +filldraw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ; +path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ; +draw bb withpen pencircle scaled 1pt withcolor .625red ; +draw origin withpen pencircle scaled 5pt withcolor .625yellow ; +\stopbuffer + +\typebuffer + +% The resulting graphic has the bounding box of the fill. Note +% how the path, because it is stroked with a .5cm pen, extends +% beyond the border of the bounding box. The way this image +% shows up depends on the viewer (settings) you use to render +% the graphic. For example, in \GHOSTVIEW, if you disable +% clipping to the bounding box, only the positive quadrant of +% the graphic is shown. Further, if you enable clipping to the +% bounding box, this image will look exactly like the previous +% image created with the fill command. In many cases, it may +% be best to avoid the \type {filldraw} command. + +The resulting graphic has the bounding box of the fill. Note how the path, +because it is stroked with a .5cm pen, extends beyond the border of the previous +bounding box. The way this image shows up depends on the viewer (settings) you +use to render the graphic. For example, in \GHOSTVIEW, if you disable clipping to +the bounding box, only the positive quadrant of the graphic is shown. \footnote +{Old versions of \METAPOST\ calculated the boundingbox differently for a \type +{filldraw}: through the middle of the penpath.} + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +From the previous examples, you can conclude that the following alternative +results in a proper bounding box: + +\startbuffer +pickup pencircle scaled .5cm ; +path p ; p := unitsquare xscaled 8cm yscaled 1cm ; +fill p withcolor .625white ; +draw p withcolor .625white ; +path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ; +draw bb withpen pencircle scaled 1pt withcolor .625red ; +draw origin withpen pencircle scaled 5pt withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The \CONTEXT\ distribution comes with a set of \METAPOST\ modules, one of which +contains the \type {drawfill} macro, which provides the outer bounding box. +\footnote {Starting from version 1.0 \METAPOST\ calculates the boundingbox +differently and the distinction between \type {drawfill} and \type {filldraw} is +gone. We keep them around both for compatibility.} Next we demonstrate its use in +another, more complicated example. + +\startbuffer +picture finalpicture ; finalpicture := nullpicture ; +numeric n ; n := 0 ; bboxmargin := 0pt ; +pickup pencircle scaled .5cm ; + +def shape = + unitsquare scaled 2cm withcolor .625white ; + draw bbox currentpicture + withpen pencircle scaled .5mm withcolor .625red ; + addto finalpicture also currentpicture shifted(n*3cm,0) ; + currentpicture := nullpicture ; n := n+1 ; +enddef ; + +fill shape ; draw shape ; filldraw shape ; drawfill shape ; + +currentpicture := finalpicture ; +\stopbuffer + +\typebuffer + +Here we introduce a macro definition, \type {shape}. In \METAPOST, the start of a +macro definition is indicated with the keyword \type {def}. Thereafter, you can +insert other variables and commands, even other macro definitions. The keyword +\type {enddef} signals the end of the macro definition. The result is shown in +\in {figure} [fig:draws and fills]; watch the bounding boxes. Close reading of +the macro will reveal that the \type {fill}, \type {draw}, \type {filldraw} and +\type {drawfill} macros are applied to the first \type {unitsquare} path in the +macro. + +\placefigure + [here] + [fig:draws and fills] + {A \type {fill}, \type {draw}, \type {filldraw} and \type + {drawfill} applied to the same square.} + {\processMPbuffer} + +In this macro, \type {bbox} calls a macro that returns the enlarged bounding box +of a path. By setting \type {bboxmargin} we can influence how much the bounding +box is enlarged. Since this is an existing variable, we don't have to allocate +it, like we do with~\type{numeric n}. Unless you take special precautions, +variables are global by nature and persistent outside macros. + +\starttyping +picture finalpicture ; finalpicture := nullpicture ; +\stoptyping + +Just as \type {numeric} allocates an integer variable, the \type {picture} +primitive allocates a picture data structure. We explicitly have to set this +picture to nothing using the built||in primitive \type {nullpicture}. + +Later on, we will add the drawn paths as accumulated in \type {currentpicture} to +this \type {finalpicture} in the following manner. + +\starttyping +addto finalpicture also currentpicture shifted(n*3cm,0) ; +\stoptyping + +Since we want to add a few more and don't want them to overlap, we shift them. +Therefore we have to erase the current picture as well as increment the shift +counter. + +\starttyping +currentpicture := nullpicture ; n := n+1 ; +\stoptyping + +The \type {drawfill} macro is one of the \METAFUN\ macros. Another handy macro is +\type {boundingbox}. When used instead of \type {bbox}, you don't have to set the +margin to zero. + +\startbuffer +drawoptions (withcolor .625white) ; +path p ; p := unitsquare scaled 2cm ; +fill p shifted (3cm,0) ; +pickup pencircle scaled .5cm ; fill p shifted (6cm,0) ; +fill p shifted (9cm,0) withpen pencircle scaled .5cm ; +\stopbuffer + +\placefigure + [here] + [fig:more draws and fills] + {The influence of pens on \type {fill}.} + {\processMPbuffer} + +There is a subtle point in filling a shape. In \in {figure} [fig:more draws and +fills] you see the influence of the pen on a \type {fill} operation. An indirect +specification has no influence, and results in a filled rectangle with sharp +corners. The third rectangle is drawn with a direct pen specification which +results in a larger shape with rounds corners. However, the bounding box is the +same in all three cases. The graphic is defined as follows. This time we don't +use a (complicated) macro. + +\typebuffer + +When a graphic is constructed, its components end up in an internal data +structure in a more or less layered way. This means that as long as a graphic is +not flushed, you may consider it to be a stack of paths and texts with the paths +being drawn or filled shapes or acting as clipping paths or bounding boxes. + +When you ask for the dimensions of a graphic the lower left and upper right +corner are calculated using this stack. Because you can explicitly set bounding +boxes, you can lie about the dimensions of a graphic. This is a very useful +feature. In the rare case that you want to know the truth and nothing but the +truth, you can tweak the \type {truecorners} numeric variable. We will +demonstrate this with a few examples. + +\startbuffer +fill fullcircle scaled 1cm withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection + +\startbuffer +fill fullcircle scaled 1cm withcolor .625yellow ; +setbounds currentpicture to boundingbox currentpicture enlarged 2mm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection + +\startbuffer +fill fullcircle scaled 1cm withcolor .625yellow ; +setbounds currentpicture to boundingbox currentpicture enlarged 2mm ; +interim truecorners := 1 ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection + +\startbuffer +fill fullcircle scaled 1cm withcolor .625yellow ; +interim truecorners := 1 ; +setbounds currentpicture to boundingbox currentpicture enlarged 2mm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection + +As you can see here, as soon as we set \type {truecorners} to~1, the bounding box +settings are ignored. \footnote {Normally you will use grouping to keep the +interim local. In \METAFUN\ each figure restores this variable at the beginning.} + +There are two related macros: \type {bbwidth} and \type {bbheight} that you can +apply to a path. + +\startbuffer +fill unitcircle xscaled 4cm yscaled 2cm + withpen pencircle scaled 1mm withcolor .625red ; +draw origin -- (bbwidth(currentpicture),0) + withpen pencircle scaled 1mm withcolor .625yellow ; +draw origin -- (0,bbheight(currentpicture)) + withpen pencircle scaled 1mm withcolor .625white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +\stopsection + +Yet another helper is \type {boundingcircle}. Its effect can best be demonstrated with +a few examples: + +\startbuffer[a] +path p ; p := fullsquare scaled 2cm ; + +draw p withpen pencircle scaled 3mm withcolor .625white ; +draw center p withpen pencircle scaled 3mm withcolor .625white ; +draw boundingbox p withpen pencircle scaled 1mm withcolor .625red ; +draw boundingcircle p withpen pencircle scaled 1mm withcolor .625yellow ; +\stopbuffer + +\startbuffer[b] +path p ; p := fullcircle scaled 2cm ; + +draw p withpen pencircle scaled 3mm withcolor .625white ; +draw center p withpen pencircle scaled 3mm withcolor .625white ; +draw boundingbox p withpen pencircle scaled 1mm withcolor .625red ; +draw boundingcircle p withpen pencircle scaled 1mm withcolor .625yellow ; +\stopbuffer + +\startbuffer[c] +path p ; p := fulltriangle scaled 2cm ; + +draw p withpen pencircle scaled 3mm withcolor .625white ; +draw center p withpen pencircle scaled 3mm withcolor .625white ; +draw boundingbox p withpen pencircle scaled 1mm withcolor .625red ; +draw boundingcircle p withpen pencircle scaled 1mm withcolor .625yellow ; +\stopbuffer + +\typebuffer[a,b,c] + +You can consider the \type {boundingcircle} to be a round boundingbox. + +\startlinecorrection +\startcombination[nx=3,ny=1,location=middle] + {\processMPbuffer[a]} {square} + {\processMPbuffer[b]} {circle} + {\processMPbuffer[c]} {triangle} +\stopcombination +\stoplinecorrection + +\startsection[title={Units}] + +\index{units} + +Like \TEX, \METAPOST\ supports multiple units of length. In \TEX, these units are +hard coded and handled by the parser, where the internal unit of length is the +scaled point (\type {sp}), something on the nanometer range. Because \METAPOST\ +is focused on \POSTSCRIPT\ output, its internal unit is the big point (\type +{bp}). All other units are derived from this unit and available as numeric +instead of hard coded. + +\starttyping +mm = 2.83464 ; pt = 0.99626 ; dd = 1.06601 ; bp := 1 ; +cm = 28.34645 ; pc = 11.95517 ; cc = 12.79213 ; in := 72 ; +\stoptyping + +Careful reading reveals that only the \type {bp} and \type {in} are fixed, while +the rest of the dimensions are scalar multiples of \type {bp}. + +Since we are dealing with graphics, the most commonly used dimensions are \type +{pt}, \type {bp}, \type {mm}, \type {cm} and~\type {in}. + +\startuseMPgraphic{pt} + fill fullsquare scaled 72.27pt withcolor .625yellow ; + fill fullcircle scaled 72.27pt withcolor white ; + label("72.27pt", center currentpicture) ; +\stopuseMPgraphic +\startuseMPgraphic{bp} + fill fullsquare scaled 72bp withcolor .625yellow ; + fill fullcircle scaled 72bp withcolor white ; + label("72bp", center currentpicture) ; +\stopuseMPgraphic +\startuseMPgraphic{mm} + fill fullsquare scaled 25.4mm withcolor .625yellow ; + fill fullcircle scaled 25.4mm withcolor white ; + label("25.4mm", center currentpicture) ; +\stopuseMPgraphic +\startuseMPgraphic{cm} + fill fullsquare scaled 2.54cm withcolor .625yellow ; + fill fullcircle scaled 2.54cm withcolor white ; + label("2.54cm", center currentpicture) ; +\stopuseMPgraphic +\startuseMPgraphic{in} + fill fullsquare scaled 1in withcolor .625yellow ; + fill fullcircle scaled 1in withcolor white ; + label("1in", center currentpicture) ; +\stopuseMPgraphic + +\startlinecorrection[blank] +\hbox to \hsize + {\useMPgraphic{pt}\hss + \useMPgraphic{bp}\hss + \useMPgraphic{mm}\hss + \useMPgraphic{cm}\hss + \useMPgraphic{in}} +\stoplinecorrection + +The text in the center of the leftmost graphic is typeset by \METAPOST\ as a +label. + +\starttyping +fill fullsquare scaled 72.27pt withcolor .625yellow ; +fill fullcircle scaled 72.27pt withcolor white ; +label("72.27pt", center currentpicture) ; +\stoptyping + +In \METAPOST\ the following lines are identical: + +\starttyping +draw fullcircle scaled 100 ; +draw fullcircle scaled 100bp ; +\stoptyping + +You might be tempted to omit the unit, but this can be confusing, particularly if +you also program in a language like \METAFONT, where the \type {pt} is the base +unit. This means that a circle scaled to 100 in \METAPOST\ is not the same as a +circle scaled to 100 in \METAFONT. Consider the next definition: + +\startbuffer +pickup pencircle scaled 0 ; +fill unitsquare + xscaled 400pt yscaled -.5cm withcolor .625red ; +fill unitsquare + xscaled 400bp yscaled +.5cm withcolor .625yellow ; +drawoptions(withcolor white) ; +label.rt("400 pt", origin shifted (0, -.25cm)) ; +label.rt("400 bp", origin shifted (0, +.25cm)) ; +\stopbuffer + +\typebuffer + +When processed, the difference between a \type {pt} and \type {bp} shows rather +well. Watch how we use \type {.rt} to move the label to the right; you can +compare this with \TEX's macro \type {\rlap}. You might want to experiment with +\type {.lft}, \type {.top}, \type {.bot}, \type {.ulft}, \type {.urt}, \type +{.llft} and \type {.lrt}. + +The difference between both bars is exactly \scratchdimen = 400 bp +\advance\scratchdimen by -400 pt \the \scratchdimen \space (as calculated by +\TEX). + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Where \TEX\ is anchored in tradition, and therefore more or less uses the \type +{pt} as the default unit, \METAPOST, much like \POSTSCRIPT, has its roots in the +computer sciences. There, to simplify calculations, an inch is divided in 72 big +points, and .72pt is sacrificed. + +When you consider that \POSTSCRIPT\ is a high end graphic programming language, +you may wonder why this sacrifice was made. Although the difference between \type +{1bp} and \type {1pt} is miniscule, this difference is the source of much +(unknown) confusion. When \TEX\ users talk about a \type {10pt} font, a desktop +publisher hears \type {10bp}. In a similar vein, when we define a papersize +having a width of \type {600pt} and a height of \type {450pt}, which is papersize +\type {S6} in \CONTEXT, a \POSTSCRIPT\ or \PDF\ viewer will report slightly +smaller values as page dimensions. This is because those programs claim the \type +{pt} to be a \type {bp}. [This confusion can lead to interesting discussions with +desktop publishers when they have to use \TEX. They often think that their demand +of a baseline distance of \type {13.4} is met when we set it to \type {13.4pt}, +while actually they were thinking of \type {13.4bp}, which of course in other +programs is specified using a \type {pt} suffix.] + +Therefore, when embedding graphics in \CONTEXT, we strongly recommend that you +use \type {pt} as the base unit instead. The main reason why we spend so many +words on this issue is that, when neglected, large graphics may look inaccurate. +Actually, when taken care of, it is one of the (many) reasons why \TEX\ documents +always look so accurate. Given that the eye is sensitive to distortions of far +less than \type {1pt}, you can be puzzled by the fact that many drawing programs +only provide a bounding box in rounded units. Thereby, they round to the next +position, to prevent unwanted cropping. For some reason this low resolution has +made it into the high end \POSTSCRIPT\ standard. + +In \CONTEXT\ we try to deal with these issues as well as possible. + +\stopsection + +\startsection[title={Scaling and shifting}] + +\index{scaling} +\index{shifting} + +When we draw a shape, \METAPOST\ will adapt the bounding box accordingly. This +means that a graphic has its natural dimensions, unless of course we adapt the +bounding box manually. When you limit your graphic to a simple shape, say a +rectangle, shifting it to some place can get obscured by this fact. Therefore, +the following series of shapes appear to be the same. + +\startbuffer +draw + unitsquare xscaled 6cm yscaled 1.5cm + withpen pencircle scaled 2mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +\startbuffer +draw + unitsquare shifted (.5,.5) xscaled 6cm yscaled 1.5cm + withpen pencircle scaled 2mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +\startbuffer +draw + unitsquare shifted (-.5,-.5) xscaled 6cm yscaled 1.5cm + withpen pencircle scaled 2mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +\startbuffer +draw + unitsquare xscaled 6cm yscaled 1.5cm shifted (1cm,1cm) + withpen pencircle scaled 2mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +\startbuffer +draw + unitsquare xscaled 6cm yscaled 1.5cm shifted (1.5cm,1cm) + withpen pencircle scaled 2mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +However, when we combine such graphics into one, we will see in what respect the +scaling and shifting actually takes place. + +\startbuffer +draw + unitsquare xscaled 6cm yscaled 2cm + withpen pencircle scaled 3.0mm withcolor .625yellow ; +draw + unitsquare shifted (.5,.5) xscaled 6cm yscaled 2cm + withpen pencircle scaled 3.0mm withcolor .625red ; +draw + unitsquare xscaled 6cm yscaled 2cm shifted (1cm,1cm) + withpen pencircle scaled 3.0mm withcolor .625white ; +draw + unitsquare xscaled 6cm yscaled 2cm shifted (1.5cm,1cm) + withpen pencircle scaled 1.5mm withcolor white ; +draw + unitsquare shifted (-.5,-.5) xscaled 6cm yscaled 2cm + withpen pencircle scaled 1mm withcolor black ; +draw origin withpen pencircle scaled 1mm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +As you can see, the transformations are applied in series. Sometimes this is not +what we want, in which case we can use parentheses to force the desired +behaviour. The lesson learned is that {\em scaling and shifting} is not always +the same as {\em shifting and scaling}. + +\startbuffer +draw + origin -- origin shifted ((4cm,0cm) shifted (4cm,0cm)) + withpen pencircle scaled 1cm withcolor .625white ; +draw + origin -- origin shifted (4cm,0cm) shifted (4cm,0cm) + withpen pencircle scaled 8mm withcolor .625yellow ; +draw + (origin -- origin shifted (4cm,0cm)) shifted (4cm,0cm) + withpen pencircle scaled 6mm withcolor .625red ; +draw + origin -- (origin shifted (4cm,0cm) shifted (4cm,0cm)) + withpen pencircle scaled 4mm withcolor white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +Especially when a path results from a call to a macro, using parentheses around a +path may help, as in the following example. + +\startbuffer +def unitslant = origin -- origin shifted (1,1) enddef ; +draw + unitslant xscaled 5cm yscaled 1cm + withpen pencircle scaled 1cm withcolor .625red ; +draw + (unitslant) xscaled 5cm yscaled 1cm + withpen pencircle scaled 5mm withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +The next definition of \type {unitslant} is therefore better. + +\startbuffer +def unitslant = (origin -- origin shifted (1,1)) enddef ; +draw + unitslant xscaled 5cm yscaled 1cm + withpen pencircle scaled 5mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank]\processMPbuffer\stoplinecorrection + +An even better alternative is: + +\startbuffer +path unitslant ; unitslant = origin -- origin shifted (1,1) ; +draw + unitslant xscaled 5cm yscaled 1cm + withpen pencircle scaled 5mm withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Curve construction}] + +\index{curves} + +\doifmodeelse{screen} + {\def\Xcom{3}\def\Ycom{2}\def\Zcom{\the\textheight}} + {\def\Xcom{2}\def\Ycom{3}\def\Zcom{\the\textwidth }} + +Chapter 3 of the \METAFONT\ book explains the mathematics behind the construction +of curves. Both \METAFONT\ and \METAPOST\ implement B\'ezier curves. The fact +that these curves are named after Pierre B\'ezier obscures the fact that the math +behind them originates with Serge\u{\i} Bernshte\u{\i}n. + +The points on the curve are determined by the following formula: + +\placeformula[-] +\startformula +z(t) = (1-t)^3 z_1 + 3 (1-t)^2 t z_2 + 3 (1-t) t^2 z_3 + t^3 z_4 +\stopformula + +Here, the parameter $t$ runs from $[0,1]$. As you can see, we are dealing with +four points. In practice this means that when we construct a curve from multiple +points, we act on two points and the two control points in between. So, the +segment that goes from $z_1$ to $z_4$ is calculated using these two points and +the points that \METAFONT|/|\METAPOST\ calls post control point and pre control +point. + +\startbuffer[a] +vardef dodrawmidpoints (expr a, b, c, d, n, col, m) = + save e, f, g, h, i, j ; pair e, f, g, h, i, j ; + e := .5[a,b] ; f := .5[b,c] ; g := .5[c,d] ; + h := .5[e,f] ; i := .5[f,g] ; j := .5[h,i] ; + if m= 0 : drawpoints j elseif + m= 1 : draw a--b--c--d elseif + m= 2 : draw e--f--g elseif + m= 3 : draw h--i elseif + m= 4 : draw a--e--h--j elseif + m= 5 : draw j--i--g--d elseif + m=11 : drawpoints a--b--c--d elseif + m=12 : drawpoints e--f--g elseif + m=13 : drawpoints h--i elseif + m=14 : drawpoints a--e--h--j elseif + m=15 : drawpoints j--i--g--d fi withcolor col ; + if n>1 : + dodrawmidpoints(a, e, h, j, n-1, col, m) ; + dodrawmidpoints(j, i, g, d, n-1, col, m) ; + fi ; +enddef ; + +vardef drawmidpoints (expr p, n, col, m) = + save a, b, c, d ; pair a, b, c, d ; + for x=0 upto length(p)-1 : + a := point x of p ; b := postcontrol x of p ; + d := point x+1 of p ; c := precontrol x+1 of p ; + dodrawmidpoints(a,b,c,d,n,col,m) ; + endfor ; +enddef ; +\stopbuffer + +\startbuffer[b] +path p ; p := (4cm,4cm)..(6cm,0cm)..(1cm,2cm) ; +\stopbuffer + +\startbuffer[c] +drawpath p ; +drawcontrollines p withcolor .625yellow ; +drawcontrolpoints p withcolor .625red ; +drawpoints p withcolor .625red ; +freelabel(btex $z_1$ etex, point 0 of p, center p) ; +freelabel(btex $z_2$ etex, postcontrol 0 of p, center p) ; +freelabel(btex $z_3$ etex, precontrol 1 of p, center p) ; +freelabel(btex $z_4$ etex, point 1 of p, center p) ; +freelabel(btex $z_5$ etex, postcontrol 1 of p, center p) ; +freelabel(btex $z_6$ etex, precontrol 2 of p, center p) ; +freelabel(btex $z_7$ etex, point 2 of p, center p) ; +\stopbuffer + +\startbuffer[x] +draw boundingbox p enlarged 1cm ; +setbounds currentpicture to boundingbox p enlarged 1cm ; +currentpicture := currentpicture xsized (.45*\Zcom) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,x] +\stoplinecorrection + +The previous curve is constructed from the three points $z_1$, $z_4$ and $z_7$. +The curve is drawn in \METAPOST\ by \type {z1..z4..z7} and is made up out of two +segments. The first segment is determined by the following points: + +\startitemize[packed,n] +\item point $z_1$ of the curve +\item the postcontrol point $z_2$ of $z_1$ +\item the precontrol point $z_3$ of $z_4$ +\item point $z_4$ of the curve +\stopitemize + +On the next pages we will see how the whole curve is constructed from these +quadruples of points. The process comes down to connecting the mid points of the +straight lines to the points mentioned. We do this three times, which is why +these curves are classified as third order approximations. + +The first series of graphics demonstrates the process of determining the mid +points. The third order midpoint is positioned on the final curve. The second +series focuses on the results: new sets of four points that will be used in a +next stage. The last series only shows the third order midpoints. As you can see, +after some six iterations we have already reached a rather good fit of the final +curve. The exact number of iterations depends on the resolution needed. You will +notice that the construction speed (density) differs per segment. + +\startpostponing + +% cc .. hh in order to avoid conflicts with c-... + +\startbuffer[cc] +drawpath p ; drawpoints p ; drawcontrolpoints p ; +\stopbuffer + +\startbuffer[dd] +drawmidpoints(p,1,.625red, 11) ; drawmidpoints(p,1,.625yellow, 1) ; +\stopbuffer + +\startbuffer[ee] +drawmidpoints(p,1,.625red, 12) ; drawmidpoints(p,1,.625yellow, 2) ; +\stopbuffer + +\startbuffer[ff] +drawmidpoints(p,1,.625red, 13) ; drawmidpoints(p,1,.625yellow, 3) ; +\stopbuffer + +\startbuffer[gg] +drawmidpoints(p,1,.625red, 14) ; drawmidpoints(p,1,.625yellow, 4) ; +\stopbuffer + +\startbuffer[hh] +drawmidpoints(p,1,.625red, 15) ; drawmidpoints(p,1,.625yellow, 5) ; +\stopbuffer + +\startbuffer +\startcombination[\Xcom*\Ycom] + {\processMPbuffer[a,b,cc,x]} {points} + {\processMPbuffer[a,b,cc,dd,x]} {first order curve} + {\processMPbuffer[a,b,cc,dd,ee,x]} {second order curve} + {\processMPbuffer[a,b,cc,dd,ee,ff,x]} {third order curve} + {\processMPbuffer[a,b,cc,dd,ee,gg,x]} {left side curves} + {\processMPbuffer[a,b,cc,dd,ee,hh,x]} {right side curves} +\stopcombination +\stopbuffer + +\getbuffer \page + +\startbuffer[dd] +drawmidpoints(p,1,.625red, 11) ; +drawmidpoints(p,1,.625yellow, 1) ; +\stopbuffer + +\startbuffer[ee] +for i=11, 12 : drawmidpoints(p,1,.625red, i) ; endfor ; +drawmidpoints(p,1,.625yellow, 2) ; +\stopbuffer + +\startbuffer[ff] +for i=11, 12, 13 : drawmidpoints(p,1,.625red, i) ; endfor ; +drawmidpoints(p,1,.625yellow, 3) ; +\stopbuffer + +\startbuffer[gg] +for i=11,12,13,14 : drawmidpoints(p,1,.625red, i) ; endfor ; +drawmidpoints(p,1,.625yellow, 4) ; +\stopbuffer + +\startbuffer[hh] +for i=11, 12, 13, 14, 15 : drawmidpoints(p,1,.625red, i) ; endfor ; +drawmidpoints(p,1,.625yellow, 5) ; +\stopbuffer + +\startbuffer +\startcombination[\Xcom*\Ycom] + {\processMPbuffer[a,b,cc,x]} {points} + {\processMPbuffer[a,b,cc,dd,x]} {first order points} + {\processMPbuffer[a,b,cc,ee,x]} {second order points} + {\processMPbuffer[a,b,cc,ff,x]} {third order points} + {\processMPbuffer[a,b,cc,gg,x]} {left side points} + {\processMPbuffer[a,b,cc,hh,x]} {right side points} +\stopcombination +\stopbuffer + +\getbuffer \page + +\startbuffer[cc] +drawpath p ; drawmidpoints (p,1,.625yellow, 0) ; +\stopbuffer + +\startbuffer[dd] +drawpath p ; drawmidpoints (p,2,.625yellow, 0) ; +\stopbuffer + +\startbuffer[ee] +drawpath p ; drawmidpoints (p,3,.625yellow, 0) ; +\stopbuffer + +\startbuffer[ff] +drawpath p ; drawmidpoints (p,4,.625yellow, 0) ; +\stopbuffer + +\startbuffer[gg] +drawpath p ; drawmidpoints (p,5,.625yellow, 0) ; +\stopbuffer + +\startbuffer[hh] +drawpath p ; drawmidpoints (p,6,.625yellow, 0) ; +\stopbuffer + +\startbuffer +\startcombination[\Xcom*\Ycom] + {\processMPbuffer[a,b,cc,x]} {first iteration} + {\processMPbuffer[a,b,cc,dd,x]} {second iteration} + {\processMPbuffer[a,b,cc,dd,ee,x]} {third iteration} + {\processMPbuffer[a,b,cc,dd,ee,ff,x]} {fourth iteration} + {\processMPbuffer[a,b,cc,dd,ee,ff,gg,x]} {fifth iteration} + {\processMPbuffer[a,b,cc,dd,ee,ff,gg,hh,x]} {sixths iteration} +\stopcombination +\stopbuffer + +\getbuffer \page + +\stoppostponing + +% here we pick up the thread, if we would not flush the +% pages before the next text, the reader could become +% confused + +The path in these examples is defined as follows: + +\typebuffer[b] + +If you are playing with graphics like this, the \METAFUN\ macro \type {randomize} +may come in handy: + +\startbuffer[bb] +p := p randomized (1cm,.5cm) ; +\stopbuffer + +\typebuffer[bb] + +If we apply this operation a couple of times we can see how the (control) points +vary. (Using the randomizer saves us the troubles of finding nice example +values.) The angle between the tangent as well as the distance from the parent +point determine the curve. + +\startbuffer[xx] +currentpicture := currentpicture scaled .5 ; +\stopbuffer + +\startlinecorrection[blank] +\hbox to \hsize + {\processMPbuffer[a,b,bb,c,x,xx]\hss + \processMPbuffer[a,b,bb,c,x,xx]\hss + \processMPbuffer[a,b,bb,c,x,xx]\hss + \processMPbuffer[a,b,bb,c,x,xx]} +\stoplinecorrection + +% new thread + +Just in case you are interested in how such graphical simulations can be +organized, we show simplified versions of the macros used here. (In the previous +examples we minimized the complexity of the code by using buffers, but describing +this mechanism is out of the scope of this section.) + +\startbuffer[demo] +vardef dodrawmidpoints (expr a, b, c, d, n) = + save e, f, g, h, i, j ; pair e, f, g, h, i, j ; + e := .5[a,b] ; f := .5[b,c] ; g := .5[c,d] ; + h := .5[e,f] ; i := .5[f,g] ; j := .5[h,i] ; + draw j ; + if n>1 : + dodrawmidpoints(a, e, h, j, n-1) ; + dodrawmidpoints(j, i, g, d, n-1) ; + fi ; +enddef ; + +vardef drawmidpoints (expr p, n) = + save a, b, c, d ; pair a, b, c, d ; + for x=0 upto length(p)-1 : + a := point x of p ; b := postcontrol x of p ; + d := point x+1 of p ; c := precontrol x+1 of p ; + dodrawmidpoints(a, b, c, d, n) ; + endfor ; +enddef ; +\stopbuffer + +We need to loop over all segments of a curve, where for each segment the left and +right side sub curves are handled recursively, upto the requested depth (denoted +as \type {n}). For this we define the following macros. + +\typebuffer[demo] + +\startbuffer[zero] +drawoptions (withpen pencircle scaled 5pt withcolor .625red); +\stopbuffer + +\startbuffer[extra] +drawoptions (withpen pencircle scaled 5pt withcolor .625yellow); +\stopbuffer + +We apply this macro to a simple shape: + +\startbuffer[one] +drawmidpoints (fullcircle xscaled 300pt yscaled 50pt, 1) ; +\stopbuffer + +\typebuffer[one] + +When drawn, this results in the points that makes up the +curve: + +\startlinecorrection[blank] +\processMPbuffer[demo,zero,one] +\stoplinecorrection + +We now add an extra iteration (resulting in the yellow points): + +\startbuffer[two] +drawmidpoints (fullcircle xscaled 300pt yscaled 50pt, 2) ; +\stopbuffer + +\typebuffer[two] + +and get: + +\startlinecorrection[blank] +\processMPbuffer[demo,zero,two,extra,one] +\stoplinecorrection + +We don't even need that much iterations to get a good result. The depth needed to +get a good result depends on the size of the pen and the resolution of the device +on which the curve is visualized. + +\startbuffer[zero] +drawoptions (withpen pencircle scaled 2pt withcolor .625red) ; +\stopbuffer + +\startbuffer[three] +for i=1 upto 7 : + drawmidpoints (fullcircle + xscaled (300pt+i*10pt) yscaled (50pt+i*10pt), i) ; +endfor ; +\stopbuffer + +\typebuffer[three] + +Here we show 7 iterations in one graphic. + +\startlinecorrection[blank] +\processMPbuffer[demo,zero,three] +\stoplinecorrection + +In practice it is not that trivial to determine the depth needed. The next +example demonstrates how the resolution of the result depends on the length and +nature of the segment. + +\startbuffer[four] +drawmidpoints (fullsquare + xscaled 300pt yscaled 50pt randomized (20pt,10pt), 5) ; +\stopbuffer + +\typebuffer[four] + +\startlinecorrection[blank] +\processMPbuffer[demo,zero,four] +\stoplinecorrection + +\stopsection + +\startsection[title={Inflection, tension and curl}] + +\index{inflection} +\index{tension} +\index{curl} + +The \METAPOST\ manual describes the meaning of \type {...} as \quotation {choose +an inflection||free path between these points unless the endpoint directions make +this impossible}. To use the words of David Arnold: a point of inflection is +where a path switches concavity, from concave up to concave down, for example. + +It is surprisingly difficult to find nice examples that demonstrate the +difference between \type {..} and \type {...}, as it is often \quote {impossible} +to honour the request for less inflection. We will demonstrate this with a few +graphics. + +In the four figures on the next pages, you will see that \type {...} is not +really suited for taming wild curves. If you really want to make sure that a +curve stays within certain bounds, you have to specify it as such using control +or intermediate points. In the figures that follow, the gray curves draw the +random path using \type {..} on top of yellow curves that use the \type {...} +connection. As you can see, in only a few occasions do the yellow \quote +{inflection} free curves show up. + +For those who asked for the code that produces these pictures, we now include it +here. We use a macro \type {sample} which we define as a usable graphic (nearly +all examples in this manual are coded in the document source). + +\startbuffer +\startuseMPgraphic{sample} +def sample (expr rx, ry) = + path p, q ; numeric n, m, r, a, b ; + color c ; c := \MPcolor{lightgray} ; + a := 3mm ; b := 2mm ; r := 2cm ; n := 7 ; m := 5 ; + q := unitsquare scaled r xyscaled (n,m) shifted (.5r,.5r) ; + draw q withpen pencircle scaled (b/4) withcolor .625yellow; + for i=1 upto n : for j=1 upto m : + p := (fullcircle scaled r randomized (r/rx,r/ry)) + shifted ((i,j) scaled r) ; + pickup pencircle scaled a ; + draw for k=0 upto length(p) : + point k of p .. endfor cycle withcolor c ; + draw for k=0 upto length(p) : + point k of p ... endfor cycle withcolor c ; + pickup pencircle scaled b ; + draw for k=0 upto length(p) : + point k of p .. endfor cycle withcolor .625yellow ; + draw for k=0 upto length(p) : + point k of p ... endfor cycle withcolor .625white ; + for k=0 upto length(p) : + draw point k of p withcolor .625red ; + endfor ; + endfor ; endfor ; + setbounds currentpicture to q ; +enddef ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +As you see, not so much code is needed. The graphics themselves were produced +with a couple of commands like: + +\startbuffer +\placefigure + {Circles with minimized inflection and 25\% randomized points.} + {\startMPcode + \includeMPgraphic{sample} ; sample(4,4) ; + \stopMPcode} +\stopbuffer + +\typebuffer + +\startpostponing + +\placefigure + {Circles with minimized inflection and 25\% randomized points.} + {\startMPcode\includeMPgraphic{sample} ; sample(4,4) ; \stopMPcode} + +\placefigure + {Circles with minimized inflection and 33\% randomized points.} + {\startMPcode\includeMPgraphic{sample} ; sample(3,3) ; \stopMPcode} + +\page + +\placefigure + {Circles with minimized inflection and 50\% randomized points.} + {\startMPcode\includeMPgraphic{sample} ; sample(2,2) ; \stopMPcode} + +\placefigure + {Circles with minimized inflection and 100\% randomized points.} + {\startMPcode\includeMPgraphic{sample} ; sample(1,1) ; \stopMPcode} + +\page + +\stoppostponing + +The tension specifier can be used to influence the curvature. To quote the +\METAPOST\ manual once more: \quotation {The tension parameter can be less than +one, but it must be at least $3/4$}. The following paths are the same: + +\starttyping +z1 .. z2 +z1 .. tension 1 .. z2 +z1 .. tension 1 and 1 .. z2 +\stoptyping + +The triple dot command \type {...} is actually a macro that makes the following +commands equivalent. Both commands will draw identical paths. + +\starttyping +z1 ... z2 +z1 .. tension atleast 1 .. z2 +\stoptyping + +The \type {atleast} directive tells \METAPOST\ to do some magic behind the +screens. Both the $3/4$ and the \type {atleast} lead directly to the question: +\quotation {What, exactly, is the influence of the tension directive?} We will +try to demystify the \type {tension} specifier through a sequence of graphics. + +\startbuffer +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; +def sample (expr p, c) = + draw p withpen pencircle scaled 2.5mm withcolor white ; + draw p withpen pencircle scaled 2.0mm withcolor c ; +enddef ; +for i=.75 step .05 until 1 : + sample (z1 .. tension i .. z2 .. z3, .625red) ; +endfor ; +for i=1 step .05 until 2 : + sample (z1 .. tension i .. z2 .. z3, .625yellow) ; +endfor ; +sample (z1 .. z2 .. z3, .625white) ; +sample (z1 ... z2 ... z3, .625white) ; +\stopbuffer + +\typebuffer + +Indeed values less than .75 give an error message, but large values are okay. As +you can see, the two gray curves are the same. Here, \type {atleast 1} means~1, +even if larger values are useful. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startbuffer +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; +def sample (expr p, c) = + draw p withpen pencircle scaled 2.5mm withcolor white ; + draw p withpen pencircle scaled 2.0mm withcolor c ; +enddef ; +for i=.75 step .05 until 1 : + sample (z1 .. tension i and 2i .. z2 .. z3, .625red) ; +endfor ; +for i=1 step .05 until 2 : + sample (z1 .. tension i and 2i .. z2 .. z3, .625yellow) ; +endfor ; +sample (z1 .. z2 .. z3, .625white) ; +sample (z1 ... z2 ... z3, .625white) ; +\stopbuffer + +Curves finally are made up out of points, and each point has two control points. +Since the \type {tension} specifier finally becomes a control point, it is not +surprising that you may specify two tension values. If we replace the tension in +the previous example by + +\starttyping +.. tension i and 2i .. +\stoptyping + +we get the following graphic: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startbuffer +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; +def sample (expr p, c) = + draw p withpen pencircle scaled 2.5mm withcolor white ; + draw p withpen pencircle scaled 2.0mm withcolor c ; +enddef ; +for i=.75 step .05 until 1 : + sample (z1 .. tension 2i and i .. z2 .. z3, .625red) ; +endfor ; +for i=1 step .05 until 2 : + sample (z1 .. tension 2i and i .. z2 .. z3, .625yellow) ; +endfor ; +sample (z1 .. z2 .. z3, .625white) ; +sample (z1 ... z2 ... z3, .625white) ; +\stopbuffer + +If we swap both values (\type {.. tension 2i and i ..}) we get: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startbuffer[a] +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; +def sample (expr p, c) = + drawpath p withpen pencircle scaled 2.5mm withcolor c ; + drawcontrollines p withcolor c ; + drawpoints p ; + drawcontrolpoints p ; +enddef ; +\stopbuffer + +We mentioned control points. We will now draw a few extreme tensions and show the +control points as \METAPOST\ calculates them. + +\startbuffer[b] +sample (z1 .. tension 0.75 .. z2 .. z3, .625red) ; +sample (z1 .. tension 2.00 .. z2 .. z3, .625yellow) ; +sample (z1 .. z2 .. z3, .625white) ; +\stopbuffer + +\typebuffer[b] + +First we will show the symmetrical tensions. + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +The asymetrical tensions are less prominent. We use the following values: + +\startbuffer[b] +sample (z1 .. tension .75 and 10 .. z2 .. z3, .625red) ; +sample (z1 .. tension 10 and .75 .. z2 .. z3, .625yellow) ; +sample (z1 .. z2 .. z3, .625white) ; +\stopbuffer + +\typebuffer[b] + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +What happens when you use the \METAPOST\ maximum value of \type {infinity} +instead of 10? Playing with this kind of graphic can be fun, especially when we +apply a few tricks. + +\startbuffer +def sample (expr p, c) = + draw p withpen pencircle scaled 2.5mm withcolor white ; + draw p withpen pencircle scaled 2.0mm withcolor c ; +enddef; + +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; + +for i=0 step .05 until 1 : + sample(z1 .. tension (.75+i) .. z2 .. z3, i[.625red,.625yellow]) ; +endfor; +\stopbuffer + +\typebuffer + +Here we change the color along with the tension. This clearly demonstrates that +we're dealing with a non linear phenomena. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +We can (misuse) transparant colors to illustrate how the effect becomes less with +growing tension. + +\startbuffer +def sample (expr p) (text c)= + draw p withpen pencircle scaled 2.0mm withcolor c ; +enddef; + +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; + +for i=0 step .05 until 1 : + sample(z1 .. tension (.75+i) .. z2 .. z3, transparent(1,1-i,.625red)) ; +endfor; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +A third magic directive is \type {curl}. The curl is attached to a point between +\type {{ }}, like \type {{curl 2}}. Anything between curly braces is a direction +specifier, so instead of a \type {curl} you may specify a vector, like \type +{{(2,3)}}, a pair of numbers, as in \type {{2,3}}, or a direction, like \type +{{dir 30}}. Because vectors and angles are straightforward, we will focus a bit +on \type {curl}. + +\starttyping +z0 .. z1 .. z2 +z0 {curl 1} .. z1 .. {curl 1} z2 +\stoptyping + +So, a \type {curl} of~1 is the default. When set to~1, the begin and|/|or end +points are approached. Given the following definitions: + +\startbuffer[a] +u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ; +def sample (expr p, c) = + draw p withpen pencircle scaled 2.5mm withcolor white ; + draw p withpen pencircle scaled 2.0mm withcolor c ; +enddef ; +\stopbuffer + +\typebuffer[a] + +We can draw three curved paths. + +\startbuffer[b] +sample (z1 {curl 0} .. z2 .. {curl 0} z3, .625red) ; +sample (z1 {curl 2} .. z2 .. {curl 2} z3, .625yellow) ; +sample (z1 {curl 1} .. z2 .. {curl 1} z3, .625white) ; +\stopbuffer + +\typebuffer[b] + +The third (gray) curve is the default situation, so we could have left the \type +{curl} specifier out of the expression. + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +\startbuffer[b] +sample (z1 {curl 0} .. z2 .. {curl 0} z3, .625red) ; +sample (z1 {curl infinity} .. z2 .. {curl infinity} z3, .625yellow) ; +sample (z1 {curl 1} .. z2 .. {curl 1} z3, .625white) ; +\stopbuffer + +The curly specs have a lower bound of zero and no upper bound. When we use +\METAPOST\ maximum value of \type {infinity} instead of~2, we get: + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +These curves were defined as: + +\typebuffer[b] + +It may sound strange, but internally \METAPOST\ can handle +larger values than \type {infinity}. + +\startbuffer[b] +sample (z1 {curl infinity} .. z2 .. {curl infinity} z3, .625red) ; +sample (z1 {curl 4infinity} .. z2 .. {curl 4infinity} z3, .625yellow) ; +sample (z1 {curl 8infinity} .. z2 .. {curl 8infinity} z3, .625white) ; +\stopbuffer + +\typebuffer[b] + +Although this is quite certainly undefined behaviour, interesting effects can be +achieved. When you turn off \METAPOST's first stage overflow catcher by setting +\type {warningcheck} to zero, you can go upto 8 times \type {infinity}, which, +being some $2^{15}$, is still far from what today's infinity is supposed to be. + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +As the built||in \METAPOST\ command \type {..} accepts the \type {curl} and \type +{tension} directives as described in this section, you will now probably +understand the following plain \METAPOST\ definitions: + +\starttyping +def -- = {curl 1} .. {curl 1} enddef ; +def --- = .. tension infinity .. enddef ; +def ... = .. tension atleast 1 .. enddef ; +\stoptyping + +These definitions also point out why you cannot add directives to the left or +right side of \type {--}, \type {---} and \type {...}: they are directives +themselves! + +\stopsection + +\startsection[title={Transformations}] + +\index{transformations} + +A \type {transform} is a vector that is used in what is called an affine +transformation. To quote the \METAPOST\ manual: + +\startquotation +If $p=(p_x,p_y)$ is a pair and $T$ is a transform, then +\type {p transform T} is a pair of the form: + +\startformula +(t_x + t_{xx} p_x + t_{xy} p_y, t_y + t_{yx} p_x + t_{yy} p_y) +\stopformula + +where the six numeric quantities $(t_x, t_y, t_{xx}, t_{xy}, +t_{yx}, t_{yy})$ determine T. +\stopquotation + +In literature concerning \POSTSCRIPT\ and \PDF\ you will find many references to +such transformation matrices. A matrix of $(s_x,0,0,s_y,0,0)$ is scaling by $s_x$ +in the horizontal direction and $s_y$ in the vertical direction, while +$(1,0,t_x,1,0,t_y)$ is a shift over $t_x,t_y$. Of course combinations are also +possible. + +Although these descriptions seem in conflict with each other in the nature and +order of the transform components in the vectors, the concepts are the same. You +normally populate transformation matrices using \type {scaled}, \type {shifted}, +\type {rotated}. + +\starttyping +transform t ; t := identity shifted (a,b) rotated c scaled d ; +path p ; p := fullcircle transformed t ; +\stoptyping + +The previous lines of code are equivalent to: + +\starttyping +path p ; p := fullcircle shifted (a,b) rotated c scaled d ; +\stoptyping + +You always need a starting point, in this case the identity matrix \type +{identity}: $(0,0,1,0,0,1)$. By the way, in \POSTSCRIPT\ the zero vector is +$(1,0,0,1,0,0)$. So, unless you want to extract the components using \type +{xpart}, \type {xypart}, \type {xxpart}, \type {ypart}, \type {yxpart} and|/|or \ +\type {yypart}, you may as well forget about the internal representation. + +You can invert a transformation using the \type {inverse} macro, which is defined +as follows, using an equation: + +\starttyping +vardef inverse primary T = + transform T_ ; T_ transformed T = identity ; T_ +enddef ; +\stoptyping + +Using transform matrices makes sense when similar transformations need to be +applied on many paths, pictures, pens, or other transforms. However, in most +cases you will use the predefined commands \type {scaled}, \type {shifted}, \type +{rotated} and alike. We will now demonstrate the most common transformations in a +text example. + +\startbuffer[a] +draw btex \bfd MetaFun etex ; +draw boundingbox currentpicture withcolor .625yellow ; +\stopbuffer + +\typebuffer[a] + +Before an independent \METAPOST\ run, the \typ {btex ... etex}'s are filtered +from the file and passed on to \TEX. After that, the \DVI\ file is converted to a +list of pictures, which is consulted by \METAPOST. This is no longer the case in +\LUATEX\ where we use \MPLIB, so users don't have to worry about these issues: +just ignore what is mentioned in the official \METAPOST\ manual. + +We can manipulate the pictures representing text like any graphic as well as draw +it with \type {draw}. + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +We show the transformations in relation to the origin and make the origin stand +out a bit more by painting it a bit larger in white first. + +\startbuffer[c] +draw origin withpen pencircle scaled 1.5mm withcolor white ; +draw origin withpen pencircle scaled 1mm withcolor .625red +\stopbuffer + +\typebuffer[c] + +The origin is in the lower left corner of the picture. + +\startlinecorrection[blank] +\processMPbuffer[a,c] +\stoplinecorrection + +Because the transformation keywords are proper english, we let the pictures speak +for themselves. + +% shifted + +\startbuffer[b] +currentpicture := currentpicture shifted (0,-1cm) ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% rotated + +\startbuffer[b] +currentpicture := currentpicture rotated 180 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% rotatedaround + +\startbuffer[b] +currentpicture := currentpicture rotatedaround(origin,30) ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% scaled + +\startbuffer[b] +currentpicture := currentpicture scaled 1.75 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% scaled + +\startbuffer[b] +currentpicture := currentpicture scaled -1 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% xscaled + +\startbuffer[b] +currentpicture := currentpicture xscaled 3.50 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% xscaled + +\startbuffer[b] +currentpicture := currentpicture xscaled -1 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% yscaled + +\startbuffer[b] +currentpicture := currentpicture yscaled .5 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% yscaled + +\startbuffer[b] +currentpicture := currentpicture yscaled -1 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% slanted + +\startbuffer[b] +currentpicture := currentpicture slanted .5 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% slanted + +\startbuffer[b] +currentpicture := currentpicture slanted -.5 ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% zscaled + +\startbuffer[b] +currentpicture := currentpicture zscaled (.75,.25) ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% reflectedabout + +\startbuffer[b] +currentpicture := currentpicture + reflectedabout(llcorner currentpicture,urcorner currentpicture) ; +\stopbuffer + +\page[preference] \typebuffer[b] \page[no] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +% reverse counterclockwise turningnumber + +A path has a certain direction. When the \type {turningnumber} of a path is +larger than zero, it runs in clockwise direction. The \METAPOST\ primitive \type +{reverse} changes the direction, while the macro \type {counterclockwise} can be +used to get a path running in a well defined direction. + +\startbuffer +drawoptions(withpen pencircle scaled 2pt withcolor .625red) ; +path p ; p := fullcircle scaled 1cm ; +drawarrow p ; +drawarrow reverse p shifted (2cm,0) ; +drawarrow counterclockwise p shifted (4cm,0) ; +drawarrow counterclockwise reverse p shifted (6cm,0) ; +drawarrow reverse counterclockwise p shifted (8cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Only this far}] + +When you take a close look at the definitions of the Computer Modern Roman fonts, +defined in the \METAFONT\ book, you will notice a high level of abstraction. +Instead of hard coded points you will find points defined in terms of \quote +{being the same as this point} or \quote {touching that point}. In this section +we will spend some time on this touchy aspect. + +\startbuffer[a] +pickup pencircle scaled 2mm ; +path p ; p := fullsquare scaled 2cm ; +draw p withcolor .625white ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +This rectangle is a scaled instance of the predefined \METAFUN\ path \type +{fullsquare} which is centered around the origin. + +\typebuffer[a] + +On this path, halfway between two of its corners, we define a point \type {q}: + +\startbuffer[b] +pair q ; q := .5[llcorner p, lrcorner p] ; +\stopbuffer + +\typebuffer[b] + +We draw this point in red, using: + +\startbuffer[c] +draw q withcolor .625red ; +\stopbuffer + +\typebuffer[c] + +As you can see, this point is drawn on top of the path. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +There are four of those midpoints, and when we connect them, we get: + +\startbuffer[c] +draw q -- q rotated 90 -- q rotated 180 -- + q rotated 270 -- cycle withcolor .625red ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +Because path \type {p} is centered around the origin, we can simply rotate point +\type {q} a few times. + +\typebuffer[c] + +There are situations, where you don't want the red path to be drawn inside +another path, or more general: where you want points to touch instead of being +overlayed. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +We can achieve this by defining point \type {q} to be located on top of the +midpoint. + +\startbuffer[b] +pair q ; q := top .5[llcorner p, lrcorner p] ; +\stopbuffer + +\typebuffer[b] + +The predefined macro \type {top} moves the point over the distance similar to the +current pen width. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +Because we are dealing with two drawing operations, and since the path inside is +drawn through the center of points, we need to repeat this move in order to draw +the red path really inside the other one. + +\startbuffer[b] +pair q ; q := top top .5[llcorner p, lrcorner p] ; +\stopbuffer + +\typebuffer[b] + +Operations like \type {top} and its relatives \type {bot}, \type {lft} and \type +{rt} can be applied sequentally. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +We already showed that \type {q} was defined as a series of rotations. + +\typebuffer[c] + +As an intermezzo we will show an alternative definition of \type {q}. Because +each point is rotated 90 degrees more, we can define a macro that expands into +the point and rotates afterwards. Because each consecutive point on the path is +rotated an additional 90 degrees, we use the \METAPOST\ macro \type {hide} to +isolate the assignment. The \type {hide} command executes the hidden command and +afterwards continues as if it were never there. You must not confuse this with +grouping, since the hidden commands are visible to its surroundings. + +\startbuffer[c] +def qq = q hide(q := q rotated 90) enddef ; +draw qq -- qq -- qq -- qq -- cycle withcolor .625red ; +\stopbuffer + +\typebuffer[c] + +The macro \type {top} uses the characteristics of the current pen to determine +the displacement. However, for the more complicated pen shapes we need a +different trick to get an inside path. Let's start by defining an elliptical +path. + +\startbuffer[a] +pickup pencircle xscaled 3mm yscaled 5mm rotated 30 ; +path p ; p := fullcircle xscaled 6cm yscaled 3cm ; +draw p withcolor .625white ; +\stopbuffer + +\typebuffer[a] + +We draw this path using a non standard pen. In the \METAFONT\ manual you will +find methods to draw shapes with similar pens, where the pen is also turning, as +it does in real calligraphy. Here we stick to a more simple one. + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +We construct the inner path from the points that make up the curve. Watch how we +use a for loop to compose the new path. When used this way, no semi colon may be +used to end the loop, since it would isolate the color directive. + +\startbuffer[b] +draw point 0 of p + for i=1 upto length(p) : -- point (i) of p endfor + withcolor .625red ; +\stopbuffer + +\typebuffer[b] + +The points are still located on the original path. + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +We can move the points to the inside by shifting them over the penwidth in the +direction perpendicular to the point. Because we use this transformation more +than once, we wrap it into a macro. This also keeps the code readable. + +\startbuffer[b] +vardef inside expr pnt of p = + (point pnt of p shifted + -(penoffset direction pnt of p of currentpen)) +enddef ; +draw inside 0 of p + for i=1 upto length(p) : -- inside i of p endfor + withcolor .625red ; +\stopbuffer + +\typebuffer[b] + +Whenever you define a pen, \METAPOST\ stores its characteristics in some private +variables which are used in the \type {top} and alike directives. The \type +{penoffset} is a built in primitive and is defined as the \quotation {point on +the pen furthest to the right of the given direction}. Deep down in \METAPOST\ +pens are actually simple paths and therefore \METAPOST\ has a notion of a point +on the penpath. In the \METAFONT\ book and \METAPOST\ manual you can find in +depth discussions on pens. + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +We're still not there. Like in a previous example, we need to shift over twice +the pen width. To get good results, we should determine the width of the pen at +that particular point, which is not trivial. The more general solution, which +permits us to specify the amount of shifting, is as follows. + +\startbuffer[b] +vardef penpoint expr pnt of p = + save n, d ; numeric n, d ; + (n,d) = if pair pnt : pnt else : (pnt,1) fi ; + (point n of p shifted + ((penoffset direction n of p of currentpen) scaled d)) +enddef ; +\stopbuffer + +\typebuffer[b] + +When the point specification is extended with a distance, in which case we have a +pair expression, the point and distance are derived from this specification. +First we demonstrate the simple case: + +\startbuffer[c] +draw penpoint 0 of p + for i=1 upto length(p)-1 : .. penpoint i of p endfor .. cycle + withcolor .625red ; +\stopbuffer + +\typebuffer[c] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +In the next graphic, we draw both an inner and and outer path. + +\startbuffer[c] +draw penpoint (0,-2) of p + for i=1 upto length(p)-1 : .. penpoint (i,-2) of p endfor .. cycle + withcolor .625red ; +draw penpoint (0,+2) of p + for i=1 upto length(p)-1 : .. penpoint (i,+2) of p endfor .. cycle + withcolor .625yellow ; +\stopbuffer + +\typebuffer[c] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c] +\stoplinecorrection + +\startbuffer[a] +path p, q, r ; + +p := fullcircle scaled 3cm ; +q := p shifted (7cm,0cm) ; +r := center p -- center q ; +\stopbuffer + +\startbuffer[b] +pair pr, qr ; + +pr := p intersectionpoint r ; +qr := q intersectionpoint r ; + +r := r cutbefore pr cutafter qr ; +\stopbuffer + +\startbuffer[c] +r := r cutbefore (point 5pt on r) ; +r := r cutafter (point -5pt on r) ; +\stopbuffer + +\startbuffer[cc] +r := r cutends 5pt ; +\stopbuffer + +\startbuffer[d] +draw p withpen pencircle scaled 10pt withcolor .625red ; +draw q withpen pencircle scaled 10pt withcolor .625yellow ; +draw r withpen pencircle scaled 20pt withcolor .625white ; +\stopbuffer + +\startbuffer[dd] +draw r withpen pencircle scaled 20pt withcolor .625white ; +draw p withpen pencircle scaled 10pt withcolor .625red ; +draw q withpen pencircle scaled 10pt withcolor .625yellow ; +\stopbuffer + +Another case when \type {top} and friends cannot be applied in a general way is +the following. Consider the three paths: + +\typebuffer[a] + +We draw these paths with: + +\typebuffer[d] + +The line is drawn from center to center and since the line has a non zero width +and a round line cap, it extends beyond this point. + +\startlinecorrection[blank] +\processMPbuffer[a,d] +\stoplinecorrection + +If we want the line to stop at the circular paths, we can cut off the pieces that +extend beyond those paths. + +\typebuffer[b] + +This time we get: + +\startlinecorrection[blank] +\processMPbuffer[a,b,d] +\stoplinecorrection + +Due to the thicker line width used when drawing the straight line, part of that +line is still visible inside the circles. So, we need to clip off a bit more. + +\typebuffer[c] + +The \type {point ... on} operation is a \METAFUN\ macro that takes a dimension. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d] +\stoplinecorrection + +In order to save you some typing, \METAFUN\ provides a macro \type {cutends} that +does the same job: + +\typebuffer[cc] + +This time we draw the path in a different order: + +\typebuffer[dd] + +That way we hide the still remaining overlapping part of the line. + +\startlinecorrection[blank] +\processMPbuffer[a,b,cc,dd] +\stoplinecorrection + +\stopsection + +\startsection[title={Directions}] + +\index{directions} + +Quite often you have to tell \METAPOST\ in what direction a line should be drawn. +A direction is specified as a vector. There are four predefined vectors: \type +{up}, \type {down}, \type {left}, \type {right}. These are defined as follows: + +\starttyping +pair up, down, left, right ; +up = -down = (0,1) ; right = -left = (1,0) ; +\stoptyping + +We can use these predefined pairs as specifications and in calculations. + +\startbuffer +dotlabel.top("up" , up * 1cm) ; +dotlabel.bot("down" , down * 1cm) ; +dotlabel.lft("left" , left * 1cm) ; +dotlabel.rt ("right", right * 1cm) ; + +drawoptions (withpen pencircle scaled .25mm withcolor .625 red) ; + +drawarrow origin -- up * 1cm ; +drawarrow origin -- down * 1cm ; +drawarrow origin -- left * 1cm ; +drawarrow origin -- right * 1cm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This graphic can also be defined in a more efficient (but probably more cryptic) +way. The next definition demonstrates a few nice tricks. Instead of looping over +the four directions, we loop over their names. Inside the loop we convert these +names, or strings, into a pair by scanning the string using \type {scantokens}. +The \type {freedotlabel} macro is part of \METAFUN\ and takes three arguments: a +label string (or alternatively a picture), a point (location), and the \quote +{center of gravity}. The label is positioned in the direction opposite to this +center of gravity. + +\startbuffer +pair destination ; +for whereto = "up", "down", "left", "right" : + destination := scantokens(whereto) * 1cm ; + freedotlabel(whereto, destination, origin) ; + drawarrow origin -- destination + withpen pencircle scaled .25mm withcolor .625 red ; +endfor ; +\stopbuffer + +\typebuffer + +So, in this code fragment, we use the string as string and (by means of \type +{scantokens}) as a point or vector. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The previous definition is a stepping stone to the next one. This time we don't +use points, but the \type {dir} command. This command converts an angle into an +unitvector. + +\startbuffer +pair destination ; +for whereto = 0 step 30 until 330 : + destination := dir(whereto) * 1.5cm ; + freedotlabel(decimal whereto, destination, origin) ; + drawarrow origin -- destination + withpen pencircle scaled .25mm withcolor .625 red ; +endfor ; +\stopbuffer + +\typebuffer + +In \METAPOST\ the angles go counter clockwise, which is not that illogical if you +look at it from the point of view of vector algebra. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Analyzing pictures}] + +\index{pictures+analyzing} + +{\em Unless you really want to know all details, you can safely skip this +section. The \METAPOST\ features discussed here are mainly of importance when you +write (advanced) macros.} + +% Later we will discuss in detail how you can use either \METAPOST\ or \TEX\ to +% typeset text (\in {section} [sec:text] and \in {chapter} [sec:typesetting]), so +% here we limit our exploration to a quick introduction. The most direct way of +% processing text in \METAPOST\ is using the \type {infont} operator. +% +% \startbuffer[mp] +% draw "this string will become a sequence of glyphs (MP)" +% infont defaultfont scaled defaultscale ; +% \stopbuffer +% +% \typebuffer[mp] +% +% The text between \type {"} is passed to \TEX, and the resulting \DVI\ will be +% converted into a picture with textual components. So, we get: +% +% \startlinecorrection[blank] +% \midaligned{\processMPbuffer[mp]} +% \stoplinecorrection +% +% The same string typeset by \TEX\ shows up as: +% +% \blank +% \midaligned{this string will become a sequence of glyphs (\TeX)} +% \blank +% +% The following \METAPOST\ features are not covered by the \METAPOST\ manual, but +% most of them are discussed in the appendix of the \type {graph} package written +% by John Hobby. +% +%It is possible to disassemble a picture by means of a special for loop using the +%\type {within} specifier. The following code walks over a picture and draws the +%components with their bounding boxes. +% +% \startbuffer[show] +% for i within currentpicture : +% draw boundingbox i withcolor .625yellow ; +% endfor ; +% \stopbuffer +% +% \typebuffer[show] +% +% We can use the disassemble loop feature to look into the previously shown +% example text. +% +% \startlinecorrection[blank] +% \processMPbuffer[mp,show] +% \stoplinecorrection +% +% The second line is typeset by \TEX. The resulting \DVI\ code is converted into a +% series of pictures, which \METAPOST\ pastes into one picture. You may also notice +% that in the set of pictures that originate in \TEX, the space is replaced by a +% shift (this is because \TEX\ knows no space). +% +% An interesting aspect of this \quote {loop over a picture} feature, is that it +% can provide insight in how \TEX\ is composing a paragraph. +% +% \startbuffer +% draw btex \framed[width=fit,align=middle]{\input tufte \relax} etex ; +% for i within currentpicture : +% draw boundingbox i withpen pencircle scaled .2pt withcolor .625yellow ; +% endfor ; +% \stopbuffer +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% You may also notice, that rules produced by \TEX\ are converted to straight line +% segments. Because the line extends 50\% of its linewidth beyond a point, there is +% a slight overshoot. This picture was defined in a few lines: +% +% \typebuffer +% +% If we use a Times Roman instead of a Palatino, we get quite +% different results. +% +% \startlinecorrection[blank] +% \startMPenvironment +% %\let\fontclass\empty +% \usetypescript[times][texnansi] +% \switchtobodyfont[times,10pt] +% \stopMPenvironment +% \processMPbuffer +% \stoplinecorrection +% +% In \CONTEXT, you can easily change the body font for +% \METAPOST\ graphics with directives like: +% +% \starttyping +% \startMPenvironment +% \usetypescript[times][texnansi] +% \switchtobodyfont[times,10pt] +% \stopMPenvironment +% \stoptyping +% +% This font has far less kerning. Even more interesting is the Lucida Bright +% Handwriting font, which is defined in such a way that no kerning is needed at +% all. +% +% \startlinecorrection[blank] +% \resetMPenvironment +% \startMPenvironment +% %\let\fontclass\empty +% \usetypescript[lucida][texnansi] +% \switchtobodyfont[lucida,hw,10pt] +% \stopMPenvironment +% \processMPbuffer +% \stoplinecorrection +% +% You can ask for the number of components with \type {length}. A component can be +% a stroked or filled path, or a text resulting from an \type {infont} operation. +% If the (last) path is a clip path, or when the whole picture has a forced +% boundingbox, the picture is treated as a whole. We will demonstrate this later. + +We can decompose \METAPOST\ pictures using a \type {within} loop. You may wonder +if such a \type {within} loop construct has any real application, and as you can +expect, it has. In \in {section} [sec:color circles] a macro is defined that +draws a colored circle. If you want the inverted alternative, you can pass the +inverted color specification, but wouldn't it be more convenient if there was an +operator that did this for you automatically? Unfortunately there isn't one so we +have to define one ourselves in a macro. + +\startbuffer +colorcircle(4cm,(.4,.6,.8),(.4,.8,.6),(.6,.4,.8)) ; +addto currentpicture also inverted currentpicture shifted (5cm,0) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +These circles were drawn using: + +\typebuffer + +When we \type {draw} a path, or stroke a path, as it is called officially, we +actually perform an addition: + +\starttyping +addto currentpicture doublepath somepath +\stoptyping + +The \type {fill} command is actually: + +\starttyping +addto currentpicture contour somepath +\stoptyping + +We will need both \type {doublepath} and \type {contour} operations in the +definition of \type {inverted}. + +When \METAPOST\ has digested a path into a picture, it keeps track of some +characteristics. We can ask for them using \type {part...} operators. The +following operators can be applied to a transform vector (one of \METAPOST's data +types), but also to a picture. Say that we have drawn a circle: + +\startbuffer[a] +draw fullcircle + xscaled 3cm yscaled 2cm + dashed dashpattern(on 3mm off 3mm) + withpen pencircle scaled 1mm + withcolor .625red ; +picture p ; p := currentpicture ; +\stopbuffer + +\typebuffer[a] + +This circle looks like: + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +We can now ask for some of the characteristics of \type {currentpicture}, like +its color. We could write the values to the log file, but it is more convenient +to put them on paper. + +\startbuffer[b] +label.rt("redpart: " & decimal redpart p, (4cm,+.5cm)) ; +label.rt("greenpart: " & decimal greenpart p, (4cm, 0cm)) ; +label.rt("bluepart: " & decimal bluepart p, (4cm,-.5cm)) ; +\stopbuffer + +\typebuffer[b] + +Here the \type {&} glues strings together, while the decimal operator converts a +number into a string. + +The result has no typographic beauty |<|keep in mind that here we use \METAPOST\ +to typeset the text|>|but the result serves its purpose. + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +We can also ask for the path itself (\type {pathpart}), the pen (\type {penpart}) +and the dashpattern (\type {dashpart}), but these can only be assigned to +variables of the corresponding type. + +A path can be stroked or filled, in which case it is a cyclic path. It can have a +non natural bounding box, be a clip path, consist of line segments or contain +text. All these characteristics can be tested. + +\startbuffer[b] +label.rt("filled: " & condition filled p, (4cm,+1.25cm)) ; +label.rt("stroked: " & condition stroked p, (4cm,+0.75cm)) ; +label.rt("textual: " & condition textual p, (4cm,+0.25cm)) ; +label.rt("clipped: " & condition clipped p, (4cm,-0.25cm)) ; +label.rt("bounded: " & condition bounded p, (4cm,-0.75cm)) ; +label.rt("cycle: " & condition cycle pathpart p, (4cm,-1.25cm)) ; +\stopbuffer + +\typebuffer[b] + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +In this code snippet, \type {condition} is a macro that takes care of translating +a boolean value into a string (like \type {decimal} does with a numeric value). + +\starttyping +def condition primary b = + if b : "true" else : "false" fi +enddef ; +\stoptyping + +Clip paths and bounding boxes are kind of special in the sense that they can +obscure components. The following examples demonstrate this. In case of a clip +path or bounding box, the \type {pathpart} operator returns this path. In any +case that asking for a value does not make sense |<|a clipping path for instance +has no color|>| a zero (null) value is returned. + +\startbuffer[b] +n := 1 ; +for i within currentpicture : n := n + 1 ; + label("n: " & decimal n & " / " & + "length: " & decimal length i & " / " & + "stroked: " & condition stroked i & " / " & + "clipped: " & condition clipped i & " / " & + "bounded: " & condition bounded i , (0,-n*.5cm)) ; +endfor ; +\stopbuffer + +\startbuffer[c] +\startlinecorrection[blank] +\framed[offset=overlay,frame=off,background=color,backgroundcolor=gray]{\processMPbuffer[a,b]} +\stoplinecorrection +\stopbuffer + +\startbuffer[a] +draw fullcircle withpen pencircle scaled 6mm ; +clip currentpicture to fullcircle ; +setbounds currentpicture to fullcircle ; +\stopbuffer + +\typebuffer[a] \getbuffer[c] + +\startbuffer[a] +draw fullcircle withpen pencircle scaled 6mm ; +setbounds currentpicture to fullcircle ; +clip currentpicture to fullcircle ; +\stopbuffer + +\typebuffer[a] \getbuffer[c] + +\startbuffer[a] +clip currentpicture to fullcircle ; +draw fullcircle withpen pencircle scaled 6mm ; +setbounds currentpicture to fullcircle ; +\stopbuffer + +\typebuffer[a] \getbuffer[c] + +\startbuffer[a] +clip currentpicture to fullcircle ; +setbounds currentpicture to fullcircle ; +draw fullcircle withpen pencircle scaled 6mm ; +\stopbuffer + +\typebuffer[a] \getbuffer[c] + +\startbuffer[a] +setbounds currentpicture to fullcircle ; +clip currentpicture to fullcircle ; +draw fullcircle withpen pencircle scaled 6mm ; +\stopbuffer + +\typebuffer[a] \getbuffer[c] + +\startbuffer[a] +setbounds currentpicture to fullcircle ; +draw fullcircle withpen pencircle scaled 6mm ; +clip currentpicture to fullcircle ; +\stopbuffer + +\typebuffer[a] \getbuffer[c] + +The description lines were generated by the following loop: + +\typebuffer[b] + +% % The following is no longer valid in MetaFun: +% +% If we have a textual picture, we can also ask for the text and font. Take the +% following picture: +% +% \startbuffer[a] +% picture p ; +% p := "MetaFun" normalinfont "rm-lmr10" scaled 2 rotated 30 slanted .5 ; +% p := p shifted (0,-ypart center p) ; +% currentpicture := p ; +% \stopbuffer +% +% \typebuffer[a] +% +% Here we can ask for: +% +% \startbuffer[b] +% label.rt("textpart: " & textpart p, (4cm,+0.25cm)) ; +% label.rt("fontpart: " & fontpart p, (4cm,-0.25cm)) ; +% \stopbuffer +% +% \typebuffer[b] +% +% and get: +% +% \startlinecorrection[blank] +% \processMPbuffer[a,b] +% \stoplinecorrection +% +% We use \type {normalinfont} instead of \type {infont} because in \METAFUN\ this +% operator is overloaded and follows another route for including text. +% +% If we're dealing with a path, the transformations have ended up in the path +% specification. If we have a text picture, we can explicitly ask for the transform +% components. +% +% \startbuffer[b] +% label.rt("xpart: " & decimal xpart p, (4cm,+1.25cm)) ; +% label.rt("ypart: " & decimal ypart p, (4cm,+0.75cm)) ; +% label.rt("xxpart: " & decimal xxpart p, (4cm,+0.25cm)) ; +% label.rt("xypart: " & decimal xypart p, (4cm,-0.25cm)) ; +% label.rt("yxpart: " & decimal yxpart p, (4cm,-0.75cm)) ; +% label.rt("yypart: " & decimal yypart p, (4cm,-1.25cm)) ; +% \stopbuffer +% +% \typebuffer[b] +% +% \startlinecorrection[blank] +% \processMPbuffer[a,b] +% \stoplinecorrection +% +% We will now define the \type {inverted} macro using these primitives. Because we +% have to return a picture, we cannot use \type {draw} and \type {fill} but need to +% use the low level operators. Because a picture can consist of more than one path, +% we need a temporary picture \type {pp}. +% +% \starttyping +% vardef inverted expr p = +% save pp ; picture pp ; pp := nullpicture ; +% for i within p : +% addto pp +% if stroked i or filled i : +% if filled i : contour else : doublepath fi pathpart i +% dashed dashpart i withpen penpart i +% else : +% also i +% fi +% withcolor white-(redpart i, greenpart i, bluepart i) ; +% endfor ; +% pp +% enddef ; +% \stoptyping +% +% We probably need to handle a few more border cases, but for general purposes, +% this macro works as expected. + +The textual capabilities built in \METAPOST\ are rather limited but in \CONTEXT\ +we have overloaded the relevant operators. There we hook into the normal font +handler. The native text related operators are: + +\starttyping +draw "MetaFun" infont "somefont" scaled 2 rotated 30 slanted .5 ; +draw btex MetaFun etex scaled 2 rotated 30 slanted .5 ; +\stoptyping + +The \type {infont} operator directly calls for a font and in stock \METAPOST\ is +limited to (eight bit) \TYPEONE\ fonts. In \CONTEXT\ you can do this: + +\startbuffer[a] +draw "MetaFun" infont "SerifBold*default" xscaled 5 rotated 5 slanted .5 ; +\stopbuffer + +\typebuffer[a] + +The specification is a regular \CONTEXT\ font specification. + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +The \type {btex ... etex} variant in normal \METAPOST\ delegates to \TEX\ and in \MKII\ +indeed we filter them and process them between runs (or at runtime). In \MKIV\ they are +also handled by \TEX\ but in an even more integrated and immediate way. + +The two primitives \type {textpart} and \type {fontpart} that can be used to disassemble +a picture don't apply to \METAFUN\ as contrary to \METAPOST\ we don't convert the result +to a picture. In later chapters we will discuss text in more detail. + +From the previous examples it may be clear that each picture has some associated +data stored with it. From the \type {bounded} boolean test we can conclude that +the bounding box is part of this data. Internally \METAPOST\ keeps track of two +bounding boxes: the natural one, and the forced one. The forced one is actually a +component of the picture which applies to all previously added graphics. You can +calculate the bounding box from the \type {llcorner} and \type {urcorner} or if +you like \type {ulcorner} and \type {lrcorner} and the \METAFUN\ command \type +{boundingbox} does so. + +The four corners that make up the bounding box are either the natural ones, or +the ones forced by \type {setbounds}. You can force \METAPOST\ to report the +natural ones by setting \type {truecorners} to~1. The next example demonstrates +this feature. + +\startbuffer +pickup pencircle scaled 2mm ; path p, q ; +draw fullcircle + scaled 4cm slanted .5 withcolor .625white ; +setbounds currentpicture to + boundingbox currentpicture enlarged -5mm ; +interim truecorners := 0 ; p := boundingbox currentpicture ; +interim truecorners := 1 ; q := boundingbox currentpicture ; +pickup pencircle scaled 1mm ; +draw p withcolor .625red ; +draw q withcolor .625yellow ; +\stopbuffer + +\typebuffer + +We use \type {interim} because \type {truecorners} is an internal \METAPOST\ +variable. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +% % we already redefined infont so it's kind of dangerous to provide this example +% +% Since \METAPOST\ can handle fonts (it can even generate font metric files) it is +% no surprise that we can also ask for the natural size of a font. For this we use +% \type {fontsize}. However, you should beware of the fact that the size reported +% is in base points. Since this is \METAPOST's native unit, this is no problem in +% calculations, but it may look confusing when you \type {show} this size on your +% terminal and get less that 10 reported for a \type {cmr10} font. +% +% \starttyping +% show fontsize "cmr10" ; +% \stoptyping +% +% In order to demonstrate that \type {fontsize} is useful, we extend the \type +% {infont} command. In the process we show a few macro definition tricks. What we +% want is a \TEX\ like specification of a font size: +% +% \startbuffer[txt] +% draw "MetaFun" infont defaultfont at 20pt ; +% \stopbuffer +% +% \typebuffer[txt] +% +% We can store the current meaning of a primitive or macro in a new macro. We do so +% with \type {infont}: +% +% \startbuffer[a] +% let normalinfont = infont ; +% \stopbuffer +% +% \typebuffer[a] +% +% We can only know the size if we know the name of the font, so we have to redefine +% \type {infont} to pick up this name. +% +% \startbuffer[b] +% numeric lastfontsize ; lastfontsize = fontsize defaultfont ; +% \stopbuffer +% +% \startbuffer[c] +% primarydef infont primary name = % patched: def should work too +% hide(lastfontsize := fontsize name) +% normalinfont name +% enddef ; +% \stopbuffer +% +% \typebuffer[c] +% +% Because we are replacing an operator, and since \METAPOST\ expects one, we have +% to use \type {def} instead of \type {vardef} (which is actually a kind of +% variable). For the same reason, we have to pick up a \type {primary}. If we would +% use a \typ {expr name}, we would end up in an unwanted look ahead. The \type +% {hide} macro hides the assignment and makes this macro behave like a \type +% {vardef} with respect to hiding expressions. We may not put a semi colon after +% the \type {)} because it would stop \METAPOST\ from reading on, and thereby +% invoke an error message. +% +% We can now define \type {at}. This macro picks up an expression (which can be +% more than just a number) and return a scale transform that normalizes the given +% size to the design size. +% +% \startbuffer[d] +% def at expr size = +% scaled (size/lastfontsize) +% enddef ; +% \stopbuffer +% +% \typebuffer[d] +% +% Because this macro is defined global, and therefore can be used apart from \type +% {infont}, we predefine the size: +% +% \typebuffer[b] +% +% When defined this way \type {at} a comfortable 20 points, the string \type +% {MetaFun} comes out as follows: +% +% \startlinecorrection[blank] +% \processMPbuffer[a,b,c,d,txt] +% \stoplinecorrection + +\stopsection + +\startsection[title={Filling}] + +\index{filling} +\index{reversing} + +In most cases a path ends up being drawn or filled. When filling a path, it +doesn't matter in what direction the path runs, as long as it's closed you're +fine. You can however change the direction any time along the path. Here is an +example of what happens when you fill a path that is partially reversed. + +\startbuffer +fill fullsquare rotated 45 scaled 2cm + withcolor .625 red ; +fill fullcircle scaled 2cm -- reverse fullcircle scaled 1cm -- cycle + withcolor .625 yellow ; +\stopbuffer + +\typebuffer + +You'll notice that the inner circle is not filled: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Now watch the following: + +\startbuffer +fill + fullsquare rotated 45 scaled 2cm + -- fullcircle scaled 2cm + -- cycle + withcolor .625 red ; +\stopbuffer + +\typebuffer + +This results in: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Compare this with: + +\startbuffer +fill + fullsquare rotated 45 scaled 2cm + -- reverse fullcircle scaled 2cm -- cycle + -- cycle + withcolor .625 red ; +\stopbuffer + +\typebuffer + +giving: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The normal filling happens according to the non||zero winding rule. An alternative is the +odd||even rule. There we don't need the reverse trick: + +\startbuffer +eofill fullsquare rotated 45 scaled 2cm + -- fullcircle scaled 2cm -- cycle + withcolor .625 red ; +\stopbuffer + +\typebuffer + +The \type {eofill} is a \METAFUN\ extension. Hopefully the next explains a bit +how this works (you can find explanations zon the internet). + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startuseMPgraphic{demo} + def DrawIt(text how) = + path p ; p := ((0,0) .. (1,0) .. (1,1) .. (0,1) .. (1,0) .. (2,1) .. cycle) scaled 2cm ; + how p withcolor .625 yellow ; + draw p withcolor .625 red ; + for i=0 step 0.05 until 1 : + fill arrowheadonpath (p,i) + withcolor .625 red ; + endfor ; + draw (0.5,0.5) scaled 2cm withpen pencircle scaled .5mm withcolor .375 white ; + draw ((0.5,0.5) scaled 2cm -- llcorner p) withpen pencircle scaled .5mm withcolor .375 white ; + draw (1.5,1.5) scaled 2cm withpen pencircle scaled .5mm withcolor .375 white ; + draw ((1.5,1.5) scaled 2cm -- urcorner p) withpen pencircle scaled .5mm withcolor .375 white ; + enddef ; +\stopuseMPgraphic + +\startlinecorrection[blank] + \startcombination[distance=4em] + {\startMPcode \includeMPgraphic{demo} DrawIt(eofill) \stopMPcode} {\type{eofill}} + {\startMPcode \includeMPgraphic{demo} DrawIt(fill) \stopMPcode} {\type{fill}} + \stopcombination +\stoplinecorrection + +In the case of a normal fill, the non||zero winding rule is applied: a winding +number is calculated by subtracting 1 each time the line (from inside an area to +someplace outside) is crossed clockwise while 1 is added each time we cross +anti||clockwise. When the total is non zero the area is filled. Here we run in one +direction and therefore we always get a fill. In the previous example where we +used a reverse, an anti||clockwise crossing was nilled by a clockwise one. + +The leftmost shape uses \type {eofill} and therefore the odd||even rule gets +applied. This time we follow the line and when it gets crossed en even number of +times the area will not be filled. + +A glyph is often constructed from more than one path and eventually the shape is +filled with an odd||even fill (\type {eofill}) operation. Take the following +sequence: + +\startbuffer +pickup pencircle scaled 1mm ; +draw fullsquare scaled 2cm ; +draw fullsquare scaled 2cm shifted (1cm,0) ; +draw fullsquare scaled 2cm shifted (0,1cm) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +We can use a sequence of \type {nofill} ending with a \type {eofill} to create +a combined shape. This is not done in \METAPOST\ but in the backend. + +\startbuffer +nofill fullsquare scaled 2cm ; +nofill fullsquare scaled 2cm shifted (1cm,0) ; +eofill fullsquare scaled 2cm shifted (0,1cm) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +As this is used for glyphs, we demonstrate this mechanism with a simple \type {O} +shape: + +\startbuffer +nofill fullcircle xyscaled (2cm,3cm) ; +eofill fullcircle xyscaled (1cm,2cm) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Another backend related feature is \type {fillup}. This is just a combination +of a fill and a draw in one go. It can save some bytes in the output file. + +\startbuffer +draw image ( + pickup pencircle scaled 5mm ; + fill fullsquare scaled 2cm ; + draw fullsquare scaled 2cm ; + fillup fullsquare scaled 2cm shifted (4cm,0) ; +) withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Pitfalls}] + +When writing macros, you need to be careful in what +operations apply to what object. There is for instance a +difference between the following code: + +\startbuffer +pickup pencircle scaled 2pt ; +draw (0,0)--(0,1)--(1,1) scaled 1cm withcolor .625 red ; +draw ((0,0)--(0,1)--(1,1)) scaled 2cm withcolor .625 yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The \type {scaled} operates on the previous expression which in the first case is +the point \type {(1,1)} and in the second case the whole path. + +\startbuffer +pickup pencircle scaled 2pt ; +draw (0,0)--(0,1)--(1,1)--cycle scaled 1cm withcolor .625 red ; +draw ((0,0)--(0,1)--(1,1)--cycle) scaled 2cm withcolor .625 yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Here the last element in the first case is not the cycle, and the next +alternative does not help us much in discovering what is going on. (Well, at +least something {\em is} going on, because the result seems to have some +dimensions.) + +\startbuffer +pickup pencircle scaled 2pt ; +draw (1,1)--cycle scaled 1cm withcolor .625 red ; +draw ((1,1)--cycle) scaled 1cm withcolor .625 yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The next lines demonstrate that we're dealing with the dark sides of \METAPOST, +and from that we may conclude that in case of doubt it's best to add parenthesis +when such fuzzy situations threaten to occur. + +\startbuffer +pickup pencircle scaled 2pt ; +draw (0,1)--(1,1)--cycle scaled 1cm withcolor .625 red ; +draw ((0,1)--(1,1)--cycle) scaled 1cm withcolor .625 yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +There are more cases where the result may surprise you. Take the following code: + +\startbuffer +drawarrow ((0,0)--(10,0)) + withpen pencircle scaled 2pt + withcolor red randomized (.4,.9) ; +currentpicture := currentpicture scaled 8 ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The arrow is made up out of two pieces and each piece gets a different shade of +red. This is because the attributes are collected and applied to each of the +components that make up the arrow. Because for each component the attribute code +is expanded again, we get two random colors. One way around this is to apply the +color afterwards. + +\startbuffer +draw + image (drawarrow ((0,0)--(10,0)) withpen pencircle scaled 2pt) + scaled 8 withcolor red randomized (.4,.9) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Here the \type {image} macro creates a picture and as you can see, this provides +a way to draw within a draw operation. + +Once you see the benefits of \type {image}, you will use it frequently. Another +handy (at first sight strange) macro is \type {hide}. You can use this in +situations where you don't want code to interfere. + +\starttyping +def mydraw text t = + boolean error ; error := false ; + def withpencil expr p = hide (error := true) enddef ; + draw t ; + if error : message "pencils are not supported here" fi ; +enddef ; +mydraw fullcircle scaled 10cm withpencil sharp ; +\stoptyping + +Here, setting the boolean normally interferes with the draw operation, but by +hiding the assignment, this code becomes valid. This code will bring the message +to your terminal and log file. + +Once you start using expressions you have a good chance of encountering messages +with regard to redundant expressions. The following code is for instance a +recipe for problems: + +\starttyping +z1 = (1,0) ; z1 = (2,0) ; +\stoptyping + +Changing the \type {=} into \type {:=} helps, but this may not be what you want. + +Because the \type {z}||variables are used frequently, they are reset each figure. +You can also reset them yourself, using the \type {clearxy} macro. The \METAFUN\ +version clears all \type {z}||variables, unless you explictly specify what +variables to reset. \footnote {This version resulted from a discussion on the +\METAFONT\ discussion list and is due to Bogus\l{}aw Jackowski.} If you want to +play with this macro, see what happens when you run the following code: + +\starttyping +show x0 ; z0 = (10,10) ; +show x0 ; x0 := whatever ; y0 := whatever ; +show x0 ; z0 = (20,20) ; +show x0 ; clearxy 0 ; +show x0 ; z0 = (30,30) ; +\stoptyping + +So, the following calls are all legal: + +\starttyping +clearxy ; clearxy 1 ; clearxy 1, 8, 10 ; +\stoptyping + +Keep in mind that for each figure a full clear is done anyway. You should not +confuse this command with \type {clearit}, which clears \type {currentpicture}. + +\stopsection + +\startsection[title={\TeX\ versus \MetaPost}] + +If you are defining your own \TEX\ and \METAPOST\ macros, you will notice that +there are a couple of essential differences between the two macro languages. In +\TEX\ the following code is invalid. \footnote {In \ETEX\ the calculation can be +done in less lines using a \type {\numexpr}.} + +\starttyping +\def\fancyplied#1% + {\ifnum#1=0 + \message{zero argument}% + \fi + \count0=#1 \multiply \count0 by \count0 + \count2=#1 \multiply \count2 by 2 + \count4=#1 \divide \count4 by 2 + \advance \count0 by \count2 + \advance \count0 by \count4 + \count4 } +\hskip \fancyplied{3} pt +\stoptyping + +This is because \TEX\ is very strict in what tokens it expects next. In +\METAPOST\ however, you can use \type {vardef}'d macros to hide nasty +intermediate calculations. + +\starttyping +vardef fancyplied expr x = + if x=0 : message "x is zero" ; (x*x+2x+x/2) +enddef ; +a := a shifted (fancyplied 3pt,0) ; +\stoptyping + +Hiding intermediate calculations and manipulations is a very strong point of +\METAPOST. + +Another important difference between both languages is the way grouping is +implemented. Because \TEX\ is dealing with a flow of information, strong grouping +is a must and therefore part of the language. Occasionally you run into +situations where you wished that you could reach over a group (for instance in +order to pass a value). + +In \METAPOST\ grouping behaves quite different. First of all, it provides the +mechanism that hides processing from the current flow. The previously mentioned +\type {vardef} is implicitly grouped. Contrary to \TEX, in \METAPOST\ all +assignments are global by default, even in a group. If you assign a variable +inside a group it is persistent unless you first save the variable (or macro) +using the \type {save} operator. + +So, in the next code snippet, the value of \type {\value} inside the box is {\em +no} but after the box is typeset, it will be {\em yes} again. + +\starttyping +\def\value{yes} \hbox{\def\value{no}\value} \value +\stoptyping + +To make a value local in \METAPOST, the following code is needed. + +\starttyping +string value ; value := "yes" ; +def intermezzo + begingroup ; + save value ; string value ; value := "no" ; + endgroup ; +enddef ; +\stoptyping + +Once you start writing your own \METAPOST\ macros, you will appreciate this +\quote {always global} behaviour. As with other differences between the two +languages, they make sense if you look at what the programs are supposed to do. + +\stopsection + +\startsection[title={Internals and Interims}] + +\index{internals} +\index{interims} + +Related to grouping is the internal numeric datatype. When numeric variables are +defined as interim, you can quickly overload them inside a group. + +\starttyping +newinternal mynumber ; mynumber := 1 ; + +begingroup ; ... interim mynumber := 0 ; ... ; endgroup ; +\stoptyping + +You can only \type {interim} a variable if it is already defined using \type +{newinternal}. + +Among the \METAPOST\ macros is one called \type {drawdot}. This macro is kind of +redundant because, at least at first sight, you can use draw to achieve the same +result. There is however a very subtle difference: a dot is slightly larger than +a drawn point. We guess that it's about the device pixel, so you may not even +notice it. It may even be due to differences in accuracy of the methods to render +them. + +\startbuffer +pickup pencircle scaled 50pt ; +drawdot origin shifted (-120pt,0) ; draw origin shifted (-60pt,0) ; +drawdot origin ; draw origin withcolor white ; +setbounds currentpicture to boundingbox currentpicture enlarged 1pt ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title=Named colors] + +The \type {withcolor} operator accepts a color expression but in \METAFUN\ it +also accepts a string indicating a color defined at the \TEX\ end. Most helpers +that deal with colors are able to deal with named colors as well. Here are some +examples. First we define a few colors: + +\startbuffer +\definecolor[MyColor1][r=.5] +\definecolor[MyColor2][g=.5] +\definecolor[MyColor3][b=.5] +\definecolor[MyColor4][s=.8] +\stopbuffer + +\typebuffer \getbuffer + +Here we access them: + +\startbuffer +fill fullcircle scaled 12 withcolor "MyColor1" ; +fill fullcircle scaled 10 withcolor "MyColor2" ; +fill fullcircle scaled 8 withcolor complementary "MyColor3" ; +fill fullcircle scaled 6 withcolor complemented "MyColor3" ; +fill fullcircle scaled 4 withcolor "MyColor4" randomized 2 ; +fill fullcircle scaled 2 withcolor "MyColor4" randomized 2 ; +addbackground + withcolor .5[resolvedcolor("MyColor4"),resolvedcolor("MyColor2")] ; +currentpicture := currentpicture ysized 4cm ; +\stopbuffer + +\typebuffer + +And get: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title=Formatted text] + +Text support in \METAFUN\ has evolved quite a bit over years. For compatibility +reasons we keep old methods around but in practice one can probably do all with +the following: + +\starttabulate[|T|p|] +\NC textext[.anchor](str) \NC position a text relative to the origin \NC \NR +\NC thetextext[.anchor](str,pos) \NC position a text relative to the given position \NC \NR +\NC rawtextext[.anchor](str,pos) \NC idem but with less checking \NC \NR +\stoptabulate + +If needed all functionality could be combined in one call (textext) but we keep +it this way. + +You need to keep in mind that text in \METAPOST\ is not a first class object but +something virtual that is known to \METAFUN\ as something with path like properties +but is actually dealt with in the backend. This means that timing is important. + +\starttyping +\startMPinitializations +picture p ; p := image(draw textext("Foo");); +\stopMPinitializations + +\startMPcode + picture q ; q := image(draw textext("Bar");); + picture r ; r := image(draw textext("Gnu");); + draw p ; + draw q shifted (2cm,0) ; + draw r shifted (4cm,0) ; +\stopMPcode +\stoptyping + +This will work out well because an initialization is part of a figure, but +this will fail: + +\starttyping +\startMPinclusions +picture p ; p := image(draw textext("Foo");); +\stopMPinclusions +\stoptyping + +because inclusions happen before the local textexts get initialized and +due to the multipass implementation are not seeN a second time. The order of +processing is: + +\starttabulate[|l|c|c|] +\BC action \BC first pass \BC second pass \NC \NR +\NC definitions \NC yes \NC \NC \NR +\NC extensions \NC yes \NC \NC \NR +\NC inclusions \NC yes \NC \NC \NR +\NC begin figure \NC yes \NC yes \NC \NR +\NC initializations \NC yes \NC yes \NC \NR +\NC metapost code \NC yes \NC yes \NC \NR +\NC end figure \NC yes \NC yes \NC \NR +\stoptabulate + +The graph package (that comes with \METAPOST) has some pseudo typesetting on +board needed to format numbers. Because we don't want to interfere with the +definitions of macros used in that package we provide another set of macros for +formatting: \type {fmttext}, \type {thefmttext} and \type {rawfmttext}. + +\startbuffer +\startMPcode +draw thefmttext("\bf@3.2f done",123.45678) withcolor darkred ; +\stopMPcode +\stopbuffer + +\typebuffer + +Here we pass one variable to the format but there can be more: \inlinebuffer. In +\LUA\ the \type {%} is used as format directive but that does not work well in +\TEX\ and \LUA\ which is why we use \type {@} instead. The formatting is done +with the formatters subsystem which is an extension to the regular \LUA\ \type +{format} function. More information can be found in \type {clf-mkiv.pdf} but one +extension is not mentioned there: \type {%!texexp!}. This directive takes one +argument by default but optionally can take one or two extra arguments: the +format of the base number and one for the exponent. The following code +demonstrates this: + +\startbuffer +\startMPcode{doublefun} +draw image ( + draw thefmttext.rt("@!texexp!", 10.4698E30, (0,-1LineHeight)) ; + draw thefmttext.rt("@1!texexp!",10.4698E30, (0,-2LineHeight)) ; + draw thefmttext.rt("@2!texexp!",10.4698E30,"@2.3f", (0,-3LineHeight)) ; + draw thefmttext.rt("@3!texexp!",10.4698E30,false,"@2i", (0,-4LineHeight)) ; + draw thefmttext.rt("@3!texexp!",10.4698E30,"@2.3f","@2i",(0,-5LineHeight)) ; +) withcolor darkblue ; +\stopMPcode +\stopbuffer + +\typebuffer + +We switch to double mode because we use large numbers. + +\startlinecorrection[blank] + \getbuffer +\stoplinecorrection + +Of course this extra formatter is also supported in the \type {context} +command: + +\startbuffer +\startluacode +context("%!texexp!, ", 10.4698E30) +context("%1!texexp!, ", 10.4698E30) +context("%2!texexp!, ", 10.4698E30,"@2.3f") +context("%3!texexp! and ",10.4698E30,false,"@2i") +context("%3!texexp!", 10.4698E30,"@2.3f","@2i") +\stopluacode +\stopbuffer + +\typebuffer + +This gives: \inlinebuffer . + +\stopsection + +\startsection[title=Lists (aka suffixed variables)] + +Sometimes graphics are constructed using lists. There are a few helpers (and +maybe there will be some more) that can make things a bit easier. Say that we +do this: + +\startbuffer +pair a[] ; +a[1] := (0,0) ; a[2] := (1,0) ; +a[3] := (1,1) ; a[4] := (0,1) ; +a[5] := (1,1) ; a[6] := (2,0) ; + +draw topath(a,--) ysized 2cm + withpen pencircle scaled 1mm + withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The \type {topath} macro converts the list into a path, in this case an ugly one. + +Say that we want to get rid of the sixth entry. For that we can use the \type +{dispose} macro. You can use the dispose for any type (except a macro). + +\startbuffer +dispose(a[6]) ; +draw topath(a,--) ysized 2cm + withpen pencircle scaled 1mm + withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +We still have some duplicate entries here: + +\startbuffer +dispose(a[6]) ; +drawpoints topath(a,--) ysized 2cm + withpen pencircle scaled 1mm + withcolor .625red ; +drawpointlabels topath(a,--) ysized 2cm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +These can be removed with: + +\startbuffer +uniquelist(a) ; +draw topath(a,--) ysized 2cm + withpen pencircle scaled 1mm + withcolor .625yellow ; +drawpoints topath(a,--) ysized 2cm + withpen pencircle scaled 1mm + withcolor .625red ; +drawpointlabels topath(a,--) ysized 2cm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Sometimes a list needs to be sorted and here is the solution: + +\startbuffer +sortlist(a,nothing) ; +draw topath(a,--) ysized 2cm + withpen pencircle scaled 1mm + withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The second argument can be an operator that takes a pair variable: + +\startbuffer +sortlist(a,xpart) ; +draw topath(a,--) ysized 2cm + withpen pencircle scaled 3mm + withcolor .625red ; +sortlist(a,ypart) ; +draw topath(a,--) ysized 2cm + withpen pencircle scaled 2mm + withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Constructing a list can be sped up with the \type {tolist} macro. + +\startbuffer +pair a[], b[], c[], d[] ; +tolist(a,1,(0,0),(1,0),(1,1),(0,1)--(1,1)--(2,2)) ; +tolist(b,0,(0,0),(1,0),(1,1),(0,1)--(1,1)--(2,2)) ; +tolist(c,(0,0),(1,0),(1,1),(0,1)--(1,1)--(2,2)) ; +tolist(d,(0,0),(1,0),(1,1)) ; + +draw image ( + draw topath(a,--) shifted (0,0) ; + draw topath(b,--) shifted (3,0) ; + draw topath(c,--) shifted (6,0) ; + draw topath(d,--) shifted (9,0) ; +) ysized 2cm withpen pencircle scaled 1mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title=Segmented paths] + +\index {segmented paths}There are all kind of helpers in \METAFUN\ and some are +discussed here. In \in {figure} [fig:segmentedpaths] we see a few macros that +return a (smooth) path made from segments. You can for instance use these to do +things that use the points on a path, like anchoring text. + +\startbuffer +def DrawSomePath(text t) = + drawpath t withcolor .625red ; + drawpoints t withcolor white ; + drawpointlabels t ; +enddef ; + +DrawSomePath(circularpath(5) scaled 12cm) ; +DrawSomePath(squarepath (5) scaled 8cm) ; +DrawSomePath(linearpath (5) scaled 4cm) ; +\stopbuffer + +\typebuffer + +\startplacefigure[title={A few segmented paths.},reference=fig:segmentedpaths] + \processMPbuffer +\stopplacefigure + +\index {crossing paths}The following examples demonstrates two mechanisms. In the +image two paths are drawn on top of each other but one of them has holes where +the other one crosses. The \type {crossingunder} macro was written by Alan +Braslau as part of the node based diagram builder. In the process the arrow +drawing code was adapted to accept a picture. + +\startbuffer[a] +drawarrow image ( + draw ((fullcircle scaled 2.25cm) crossingunder (fullsquare scaled 2cm)) + withpen pencircle scaled 1mm withcolor .625green ; + draw (fullsquare scaled 2cm) + withpen pencircle scaled 1mm withcolor .625blue ; +) ; +drawarrow image ( + draw (fullsquare scaled 4cm) + withpen pencircle scaled 1mm withcolor .625red ; + draw ((fullcircle scaled 5cm) crossingunder (fullsquare scaled 4cm)) + withpen pencircle scaled 1mm withcolor .625yellow ; +) ; +\stopbuffer + +\startbuffer[b] +drawarrow image ( + draw ((fullsquare scaled 2cm) crossingunder (fullcircle scaled 2.25cm)) + withpen pencircle scaled 1mm withcolor .625blue ; + draw (fullcircle scaled 2.25cm) + withpen pencircle scaled 1mm withcolor .625green ; +) ; +drawarrow image ( + draw (fullcircle scaled 5cm) + withpen pencircle scaled 1mm withcolor .625yellow ; + draw ((fullsquare scaled 4cm) crossingunder (fullcircle scaled 5cm)) + withpen pencircle scaled 1mm withcolor .625red ; +) ; +\stopbuffer + +\typebuffer[a] + +The next variant uses a different order: + +\typebuffer[b] + +The results are shown in \in {figure} [fig:crossingunder]. The internal variable +\type {crossingscale} can be used to make the gap wider or narrower. The gap has +a default value of 20. + +\startplacefigure[title=Crossing paths without touching,reference=fig:crossingunder] + \startcombination + {\processMPbuffer[a]} {} + {\processMPbuffer[b]} {} + \stopcombination +\stopplacefigure + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-colofon-paper.tex b/doc/context/sources/general/manuals/metafun/metafun-colofon-paper.tex new file mode 100644 index 000000000..1a611a325 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-colofon-paper.tex @@ -0,0 +1,19 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-colofon-paper + +\environment metafun-environment + +\startstandardmakeup + + \vfill + + \setupalign[flushright,broad] + + \component metafun-colofon + +\stopstandardmakeup + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-colofon-screen.tex b/doc/context/sources/general/manuals/metafun/metafun-colofon-screen.tex new file mode 100644 index 000000000..590c7725f --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-colofon-screen.tex @@ -0,0 +1,21 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-colofon-screen + +\environment metafun-environment + +\page + +\start + + \setupalign[flushright,broad] + + \component metafun-colofon + +\stop + +\page + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-colofon.tex b/doc/context/sources/general/manuals/metafun/metafun-colofon.tex new file mode 100644 index 000000000..b4c162a89 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-colofon.tex @@ -0,0 +1,56 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-colofon + +\environment metafun-environment + +\introsubject{For them} + +I owe much inspiration to both my parents. My mother Jannie constantly +demonstrated me that computer graphics will never improve nature. She also +converted one of my first \METAPOST\ graphics into a patchwork that will remind +me forever that handcraft is more vivid than computer artwork. My father Hein has +spent a great deal of his life teaching math, and I'm sure he would have loved +\METAPOST. I inherited his love for books. I therefore dedicate this document to +them. + +\introsubject{Colofon} + +This manual is typeset with \CONTEXT\ \MKIV. No special tricks are used and +everything you see in here, is available for \CONTEXT\ users. The text is typeset +in Palatino and Computer Modern Typewriter. We used \LUATEX\ as \TEX\ processing +engine. Since this document is meant to be printed in color, some examples will +look sub||optimal when printed in black and white. + +\introsubject{Graphics} + +The artist impression of one of Hasselts canals at \at {page} [canal] is made by +Johan Jonker. The \CDROM\ production process graphic at \at {page} [hacker] is a +scan of a graphic made by Hester de Weert. + +\introsubject{Copyright} + +\startlines +Hans Hagen, PRAGMA Advanced Document Engineering, Hasselt NL +copyright: 1999-\currentdate[year] / version 4: \currentdate +\stoplines + +\introsubject{Publisher} + +\startlines +publisher: Boekplan, NL +isbn-ean: 978-94-90688-02-8 +website: www.boekplan.nl +\stoplines + +\introsubject{Info} + +\startlines +internet: www.pragma-ade.com +support: ntg-context@ntg.nl +context: www.contextgarden.net +\stoplines + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-contents.tex b/doc/context/sources/general/manuals/metafun/metafun-contents.tex new file mode 100644 index 000000000..0767a0248 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-contents.tex @@ -0,0 +1,17 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-contents + +\environment metafun-environment + +\starttitle[reference=content,title={Content}] + + \startcolumns + \placelist[chapter,section] + \stopcolumns + +\stoptitle + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-conventions.tex b/doc/context/sources/general/manuals/metafun/metafun-conventions.tex new file mode 100644 index 000000000..6a6072c56 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-conventions.tex @@ -0,0 +1,117 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-conventions + +\environment metafun-environment + +\startchapter[title={Conventions}] + +\index {running} +\index {processing} + +When reading this manual, you may be tempted to test the examples shown. This can +be done in several ways. You can make a file and process that file by \METAPOST. +Such a file looks like: + +\starttyping +beginfig(1) ; + fill fullcircle scaled 5cm withcolor red ; % a graphic +endfig ; + +end . +\stoptyping + +Don't forget the semi||colons that end the statements. If the file is saved as +\type {yourfile.mp}, then the file can be processed. Before we process this file, +we first need to load some basic \METAPOST\ definitions, because the built in +repertoire of commands is rather limited. Such a set is called a format. The +standard format is called {metapost} but we will use a more extensive set of +macros \type {metafun}. In the past such a set was converted into a \type {mem} +file and running the above file was done with: + +\starttyping +mpost --mem=metafun.mem yourfile +\stoptyping + +However, this is no longer the case and macros need to be loaded at startup as +follows: + +\starttyping +mpost --ini metafun.mpii yourfile.mp +\stoptyping + +Watch the suffix \type {mpii}: this refers to the stand alone, the one that +doesn't rely on \LUATEX. + +After the run the results are available in \type {yourfile.1} and can be viewed +with \GHOSTSCRIPT. You don't need to close the file so reprocessing is very +convenient. + +Because we will go beyond standard \METAPOST, we will use the \type {mpiv} files. +These work with the library which in turn means that we will run from within +\CONTEXT. This has the advantage that we also have advanced font support at our +hands. In that case, a simple file looks like: + +\starttyping +\starttext + \startMPpage + fill fullcircle scaled 5cm withcolor red ; + \stopMPpage + \startMPpage + fill unitsquare scaled 5cm withcolor red ; + \stopMPpage +\stoptext +\stoptyping + +If the file is saved as \type {yourfile.tex}, then you can produce a \PDF\ file +with: \footnote {In fact, you could also process the \METAPOST\ file directly +because the \type {context} script will recognize it as such and wrap it into +a page.} + +\starttyping +context yourfile +\stoptyping + +The previous call will use \LUATEX\ and \CONTEXT\ \MKIV\ to produce a file with +two pages using the built in \METAPOST\ library with \METAFUN. When you use this +route you will automatically get the integrated text support shown in this +manual, including \OPENTYPE\ support. If one page is enough, you can also say: + +\starttyping +\startMPpage +fill fullcircle scaled 5cm withcolor red ; +\stopMPpage +\stoptyping + +So when you have a running \CONTEXT\ on your system you don't need to bother +about installing \METAPOST\ and running \METAFUN. + +We will use lots of color. Don't worry if your red is not our red, or your yellow +does not match ours. We've made color definitions to match the overall design of +this document, but you should feel free to use any color of choice in the +upcoming examples. + +By default, \CONTEXT\ has turned its color mechanism on. If you don't want your +graphics to have color, you should say: + +\starttyping +\setupcolors[state=stop] +\stoptyping + +but in todays documents color is so normal that you will probably never do that. +Because \METAFUN\ hooks into the \CONTEXT\ color mechanism, you can also use its +color space and conversion related features. + +You need to keep in mind that just like \CONTEXT\ \MKII\ is frozen, the \type +{mpii} macros are also not extended. From now on we assume that you use \CONTEXT\ +\MKIV\ which exclusively uses \type {mpiv} macros. + +Even if you want to use \METAFUN\ but not \CONTEXT, you can still best use the +mentioned page method as it will give you decent text processing. You need to +know (and use) only a few \CONTEXT\ commands then. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-debugging.tex b/doc/context/sources/general/manuals/metafun/metafun-debugging.tex new file mode 100644 index 000000000..4174d34e1 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-debugging.tex @@ -0,0 +1,383 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent mfun-debugging + +\environment metafun-environment + +\startchapter[reference=sec:debugging,title={Debugging}] + +\index{debugging} + +\startintro + +Those familiar with \CONTEXT\ will know that it has quite some visual debugging +features build in. So, what can you expect of the \METAPOST\ macros that come +with \CONTEXT ? In this chapter we will introduce a few commands that show some +insight in what \METAPOST\ is doing. + +\stopintro + +\startsection[title=Showing paths] + +Since the outcome of \METAPOST\ code is in many respects more predictable than +that of \TEX\ code, we don't need that advanced visual debugging features. +Nevertheless we provide a few, that are all based on visualizing paths. + +\startbuffer +path p ; p := fullcircle scaled 4cm ; +drawpath p ; drawpoints p ; drawpointlabels p ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This visualization is achieved by using dedicated drawing commands: + +\typebuffer + +Since control points play an important role in defining the shape, visualizing +them may shed some insight in what \METAPOST\ is doing. + +\startbuffer +path p ; p := fullcircle xscaled 4cm yscaled 3cm ; +drawpath p ; drawcontrollines p ; +drawpoints p ; drawcontrolpoints p ; drawpointlabels p ; +\stopbuffer + +\typebuffer + +The pre and post control points show up as small dots and are connected to their +parent point with thin lines. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +You can deduce the direction of a path from the way the +points are numbered, but using an arrow to indicate the +direction is more clear. + +\startbuffer +path p ; p := fullcircle xscaled 4cm yscaled 3cm ; +drawarrowpath p ; drawcontrollines p ; +drawpoints p ; drawcontrolpoints p ; drawpointlabels p ; +\stopbuffer + +\typebuffer + +The \type {drawarrowpath} is responsible for the arrow. Especially when you are +in the process of defining macros that have to calculate intersections or take +subpaths, knowing the direction may be of help. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The next table summarizes the special drawing commands: + +\starttabulate[|lT|l|] +\HL +\NC drawpath \NC the path \NC \NR +\NC drawarrowpath \NC the direction of the path \NC \NR +\NC drawcontrollines \NC the lines to the control points \NC \NR +\NC drawpoints \NC the points that make up the path \NC \NR +\NC drawcontrolpoints \NC the control points of the points \NC \NR +\NC drawpointlabels \NC the numbers of the points \NC \NR +\HL +\stoptabulate + +You can set the characteristics of these like you set \type {drawoptions}. The +default settings are as follows: + +\starttyping +drawpathoptions (withpen pencircle scaled 5 withcolor .8white) ; +drawpointoptions (withpen pencircle scaled 4 withcolor black) ; +drawcontroloptions(withpen pencircle scaled 2.5 withcolor black) ; +drawlineoptions (withpen pencircle scaled 1 withcolor .5white) ; +drawlabeloptions () ; +\stoptyping + +Two more options are \type {draworiginoptions} and \type {drawboundoptions} which +are used when visualizing the bounding box and origin. + +\startbuffer +swappointlabels := true ; +path p ; p := fullcircle xscaled 4cm yscaled 3cm ; +drawarrowpath p ; drawcontrollines p ; +drawpoints p ; drawcontrolpoints p ; drawpointlabels p ; +drawboundingbox p ; draworigin ; +\stopbuffer + +\typebuffer + +In this example we have set \type {swappointlabels} to change the place of the +labels. You can set the variable \type {originlength} to tune the appearance of +the origin. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +You can pass options directly, like you do with \type {draw} and \type {fill}. +Those options override the defaults. + +\startbuffer +path p ; p := fullcircle xscaled 6cm yscaled 3cm rotated 15 ; +drawarrowpath p ; +drawcontrollines p withcolor .625red ; +drawpoints p withcolor .625yellow ; +drawcontrolpoints p withcolor .625yellow ; +drawpointlabels p withcolor .625yellow ; +drawboundingbox p ; +draworigin withcolor .625red ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Here we used the options: + +\typebuffer + +Sometimes it makes sense to draw a simple coordinate system, and for that purpose +we have three more macros. They draw axis and tickmarks. + +\startbuffer +drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ; +\stopbuffer + +\typebuffer + +The system drawn is based on the bounding box specification of the path passed to +the macro. You can also draw one axis, using \type {drawxticks} or \type +{drawyticks}. Here we show the previous command. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +By default, the ticks are placed at .5cm distance, but you can change this by +setting \type {tickstep} to a different value. + +\startbuffer +tickstep := 1cm ; ticklength := 2mm ; +drawticks fullsquare xscaled 4cm yscaled 3cm ; +tickstep := tickstep/2 ; ticklength := ticklength/2 ; +drawticks fullsquare xscaled 4cm yscaled 3cm ; +\stopbuffer + +\typebuffer + +The \type {ticklength} variable specifies the length of a tick. Here we +manipulated both the variables to get a more advanced system. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +If visualizing a path would mean that we would have to key in al those +draw||commands, you could hardly call it a comfortable tool. Therefore, we can +say: + +\startbuffer +drawwholepath fullsquare scaled 3cm rotated 30 randomized 5mm ; +\stopbuffer + +\typebuffer + +The \type {drawwholepath} command shows everything except the axis. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +If even this is too much labour, you may say: + +\starttyping +visualizepaths ; +\stoptyping + +This redefines the \type {draw} and \type {fill} command in such a way that they +also show all the information. + +\startbuffer +visualizepaths ; +draw fullsquare scaled 3cm rotated 30 randomized 2mm ; +\stopbuffer + +\typebuffer + +You may compare this feature to the \type {\showmakeup} command available in +\CONTEXT, that redefines the \TEX\ primitives that deal with boxes, glues, +penalties, and alike. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Of course you may want to take a look at the \METAPOST\ manual for its built in +(more verbose) tracing options. One command that may prove to be useful is \type +{show}, that you can apply to any variable. This command reports the current +value (if known) to the terminal and log file. + +\startlinecorrection[blank] +{\showmakeup\processMPbuffer} +\stoplinecorrection + +The previous picture shows what is typeset when we also say \type {\showmakeup}. +This command visualizes \TEX's boxes, skips, kerns and penalties. As you can see, +there are some boxes involved, which is due to the conversion of \METAPOST\ +output to \PDF. + +\starttyping +\startlinecorrection[blank] +... the graphic ... +\stoplinecorrection +\stoptyping + +The small bar is a kern and the small rectangles are penalties. More details on +this debugger can be found in the \CONTEXT\ manuals and the documentation of the +modules involved. + +\stopsection + +\startsection[title=Comments] + +Sometimes, when trouble strikes, you might want to peek in the \PDF\ file to see +what gets written there. Each graphic is marked with a number but when you +have many it might make sense to add a comment to help you locate the code. + +\startbuffer +\startMPcode + comment("test graphic") ; + message("processing a test graphic") ; + draw fullsquare scaled 1cm ; +\stopMPcode +\stopbuffer + +\typebuffer + +This renders as: + +\startlinecorrection[blank] + \getbuffer +\stoplinecorrection + +On the console we get these messages: + +\starttyping +metapost > message : processing a test graphic +metapost > warning : processing a test graphic +\stoptyping + +And in the \PDF\ file we will find: + +\starttyping +% mps graphic 1: begin +% mps graphic 1: test graphic +q 0 g 0 G 10 M 1 j 1 J +0.500000000 w +-14.173233032 -14.173233032 m +14.173233032 -14.173233032 l +14.173233032 14.173233032 l +-14.173233032 14.173233032 l +-14.173233032 -14.173233032 l +h S +0 g 0 G Q +% mps graphic 1: end +\stoptyping + +Here are some examples of constructed messages: + +\starttyping +message "2: okay (done)" ; +message "1: " & dq & "okay" & dq & " (done)" ; +message "3: " & quotation "okay" & " (done)" ; +message "3: " & quote "okay" & " (done)" ; +message "4: " & quotation 123 & " (done)" ; +message "5: " & quotation true & " (done)" ; +message "6: " & quote true & " (done)" ; +message "7: " & tostring true & " (done)" ; +message "8: " & tostring (1,2) & " (done)" ; +message "9: " & topair (1,2) & " (done)" ; +\stoptyping + +and this is what you get: + +\starttyping +metapost > message : 2: okay (done) +metapost > message : 1: "okay" (done) +metapost > message : 3: "okay" (done) +metapost > message : 3: 'okay' (done) +metapost > message : 4: "123" (done) +metapost > message : 5: "true" (done) +metapost > message : 6: 'true' (done) +metapost > message : 7: true (done) +metapost > message : 8: 1 2 (done) +metapost > message : 9: (1,2) (done) +\stoptyping + +\stopsection + +\startsection[title=Pens] + +A circular pen is applied to a path in a different way than for instance a +square pen. Circular pens are mapped onto \POSTSCRIPT\ pens while for other +pens an outline is calculated that gets filled. Take this code: + +\startbuffer[a] +\startMPcode + draw fullcircle xscaled 6cm yscaled 3cm + withpen pensquare scaled 5mm rotated 30 + withcolor .625yellow ; +\stopMPcode +\stopbuffer + +\startbuffer[b] +\startMPcode + draw envelope pensquare scaled 5mm rotated 30 of + (fullcircle xscaled 6cm yscaled 3cm) + withpen pencircle scaled 1mm + withcolor .375white ; +\stopMPcode +\stopbuffer + +\startbuffer[c] +\enabletrackers[metapost.forcestroke] +\startMPcode + draw fullcircle xscaled 6cm yscaled 3cm + withpen pensquare scaled 5mm rotated 30 + withcolor .625red ; +\stopMPcode +\disabletrackers[metapost.forcestroke] +\stopbuffer + +\typebuffer[a] + +and this: + +\typebuffer[b] + +and: + +\typebuffer[c] + +When we overlay these three we get. The envelope only returns the outer curve. + +\startlinecorrection[blank] +\startoverlay + {\getbuffer[a]} + {\getbuffer[b]} + {\getbuffer[c]} +\stopoverlay +\stoplinecorrection + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-document.tex b/doc/context/sources/general/manuals/metafun/metafun-document.tex new file mode 100644 index 000000000..bb5540850 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-document.tex @@ -0,0 +1,118 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-document + +\environment metafun-environment + +\startchapter[title={This document}] + +\startintro + +This document is produced in \CONTEXT\ and can serve as an example of how to +integrate \METAPOST\ graphics into \TEX. In this appendix we will discuss some +details of producing this document. + +\stopintro + +We did not use any special tricks, so most of the examples you have seen are +coded just as shown. We used buffers to ensure that the code used to produce the +accompanying graphic is identical to the typeset code in the document. Here is an +example. + +\starttyping +\startbuffer[dummy] +draw fullcircle + xscaled 3cm yscaled 2cm + rotatedaround(origin,30) + withcolor .625red ; +\stopbuffer +\stoptyping + +Instead of using \type {\getbuffer}, we used the following command: + +\starttyping +\startlinecorrection[blank] +\processMPbuffer[dummy] +\stoplinecorrection +\stoptyping + +The line correction commands take care of proper spacing around the graphic. If +you want to process more buffers at once, you can pass their names as a comma +separated list. Alternatively, we could have said: + +\starttyping +\startuseMPgraphic{dummy} + draw fullcircle + xscaled 3cm yscaled 2cm + rotatedaround(origin,30) + withcolor .625red ; +\stopuseMPgraphic +\stoptyping + +When including this graphic, we again take care of spacing. + +\starttyping +\startlinecorrection[blank] +\useMPgraphic{dummy} +\stoplinecorrection +\stoptyping + +The first version of this manual was produced with \PDFTEX\ and call|-|outs to +\METAPOST. Because the number of graphics is large, we processed that version +using the \type {--automp} directive (at that moment we were using \TEXEXEC). And +even then runtime was so unconveniently long that updating this manual became +less and less fun. The current version is produced with \LUATEX\ and \CONTEXT\ +\MKIV, which brings down the runtime (including runtime calls to independent +\CONTEXT\ runs for the outline examples) to some 45 seconds on a 2.2 Gig Dell +M90. Given that (at the time of writing this) over 1700 graphics are generated on +the fly, this is not bad at all. On my current machine, a Dell M6700 with an +Intel Core i7|-|3840QM running at 2.8 (3.9) Ghz (and Windows~8) the runtime of +the third version was just above 20 seconds all|-|in and some 25\percent\ less +when using \LUAJITTEX. When I started with updating to version 4 of this manual, +I timed about 15 seconds on the same machine (but with Windows-10) which means +that in the meantime the \CONTEXT|/|\LUATEX\ combination gained some 25\% +performance. Using the new Bash|-|On|-|Windows subsystem gives the same +performance. Of course each update adds pages so in the end we need more time +with each update but it remains a nice test case. The tight integration of \TEX, +\METAPOST\ and \LUA\ pays off. + +The document style is not that complicated. The main complication in such a +document is to make sure that \METAPOST\ is operating under the same font regime, +but in \MKIV\ this happens automatically. As document font we use the URW +Palatino for the running text combined with Computer Modern Typewriter. Because +this document is available as paper and screen document, some large graphics are +scaled down in the screen version. + +We don't use any special tricks in typesetting this document, but when we added +the section about transparency, a dirty trick was needed in a few cases in order to +get the described results. Because the screen document has gray backgrounds, +exclusive transparencies come out \quote {wrong}. In the function drawing example +we use the following trick to get a black background behind the graphics only. We +have a buffer that contains a few lines of code: + +% buffer only available in screen mode + +\starttyping +picture savedpicture ; +savedpicture := currentpicture ; +currentpicture := nullpicture ; +draw savedpicture withcolor black ; +draw savedpicture ; +\stoptyping + +Since we use buffers for the graphics as well, we can now process a buffer with +name \type {example} as follows: + +\starttyping +\processbuffer[example,wipe] +\stoptyping + +This means that the example code is included two times. After it is processed, we +recolor the currentpicture black, and after that we add the original picture once +again. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-effects.tex b/doc/context/sources/general/manuals/metafun/metafun-effects.tex new file mode 100644 index 000000000..74e7d487e --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-effects.tex @@ -0,0 +1,2596 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +% graphic text takes 5 sec on 21 + +\startcomponent metafun-effects + +\environment metafun-environment + +\useMPlibrary[outlines] + +\startchapter[reference=sec:effects,title={Special effects}] + +\startintro + +Sometimes we want to go beyond \METAPOST's native features. Examples of such an +extension are \CMYK\ colors, shading and transparency. Although features like +this should be used with care, sometimes the documents look and feel can profit +from it. + +If you don't want the whole graphic, but only a part of it, clipping comes into +play. In addition to the standard clipping features, we can use \METAPOST\ to +provide a decent clipping path. In this chapter we will uncover the details. + +We will also introduce ways to include externally defined graphics and outline +fonts. We will demonstrate that within reasonable bounds you can manipulate such +graphics. + +\stopintro + +\startsection[title={Spot colors}] + +You can define spot and multitone colors directly in \METAFUN, although normally +you will do it at the \TEX\ end for consistency. At the \TEX\ end we define this: + +\startbuffer +\definecolor [SpotBlue] [c=1,m=.38,y=0,k=.64] +\definecolor [SpotYellow] [c=0,m=.28,y=1,k=.06] +\definemultitonecolor [MultiColor] [SpotBlue=.5,SpotYellow=.25] +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +draw image ( + fill unitsquare shifted (7,0) + withcolor namedcolor("MultiColor") ; + fill unitsquare shifted (6,0) + withcolor .6 * spotcolor("temp1",red) ; + fill unitsquare shifted (5,0) + withcolor .4 * spotcolor("temp1",red) ; + fill unitsquare shifted (4,0) + withcolor .5 * spotcolor("temp2",.5green) ; + fill unitsquare shifted (3,0) + withcolor .5 * spotcolor("temp3",green) ; + fill unitsquare shifted (2,0) + withcolor multitonecolor("temp4",blue/2,yellow/2,green/2,magenta/3) ; +) xsized TextWidth ; +\stopbuffer + +Next we process this graphic: + +\typebuffer + +and get: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Transparency}] + +\index{transparency} + +{\em In the screen version we use a light gray background color. As a result, +some of the transparency methods demonstrated here give unexpected results. The +A4 version of this document demonstrates the real effects.} + +Although transparent colors have been around for some time already, it was only +around 2000 that they made it as a high level feature into document format +languages like \PDF. Supporting such a feature at a higher abstraction level is +not only more portable, but also less sensitive for misinterpretation. + +\startbuffer[mpdef] +vardef ColorCircle (expr method, factor, ca, cb, cc) = + save u, p ; path p ; p := fullcircle shifted (1/4,0) ; + image + ( fill p rotated 90 withcolor ca withtransparency (method,factor) ; + fill p rotated 210 withcolor cb withtransparency (method,factor) ; + fill p rotated 330 withcolor cc withtransparency (method,factor) ; ) +enddef ; +\stopbuffer + +\typebuffer[mpdef] + +\startbuffer[mp] +draw ColorCircle ("normal", .5, red, green, blue) xsized 3cm ; +currentpicture := currentpicture shifted (-4cm,0) ; +draw ColorCircle ("exclusion", .5, red, green, blue) xsized 3cm ; +currentpicture := currentpicture shifted (-4cm,0) ; +draw ColorCircle ("exclusion", 1, red, green, blue) xsized 3cm ; +\stopbuffer + +\typebuffer[mp] + +\startlinecorrection[blank] +\processMPbuffer[mpdef,mp] +\stoplinecorrection + +\startbuffer[mp] +cmykcolor xcyan ; xcyan := (1,0,0,0) ; +cmykcolor xmagenta ; xmagenta := (0,1,0,0) ; +cmykcolor xyellow ; xyellow := (0,0,1,0) ; + +draw ColorCircle ("exclusion", .5, xcyan, xmagenta, xyellow) xsized 3cm ; +\stopbuffer + +\typebuffer[mp] + +\startlinecorrection[blank] +\processMPbuffer[mpdef,mp] +\stoplinecorrection + +You can be tempted to use transparency as a convenient way to achieve soft +colors. In that case you should be aware of the fact that rendering transparent +colors takes more time than normal colors \footnote {When your printer does not +support this feature natively, the intermediate (\POSTSCRIPT) file send to the +printing engine is also larger.} + +Fortunatey, \METAPOST\ provides a similar mechanism. The last circle in the +following row demonstrates how we can trigger colors proportionally to other +colors. Normally \type {background} is white, but you can set predefined color +variables to another value. + +\startbuffer[mp] +path p ; p := fullcircle scaled 2cm ; +fill p shifted (0cm,0) withcolor blue ; +fill p shifted (3cm,0) withcolor .5blue ; +fill p shifted (6cm,0) withcolor transparent (1,0.5,blue) ; +fill p shifted (9cm,0) withcolor .5[blue,white] ; +\stopbuffer + +\typebuffer[mp] + +\startlinecorrection[blank] +\processMPbuffer[mp] +\stoplinecorrection + +The next series demonstrates that we use the complementary factor \type {.7} in +the \METAPOST\ soft color to achieve the same softness as the \type {.3} +transparency. + +\startbuffer[mp] +path p ; p := fullcircle scaled 2cm ; +fill p shifted (0cm,0) withcolor red ; +fill p shifted (3cm,0) withcolor .7red ; +fill p shifted (6cm,0) withcolor transparent (1,0.3,red) ; +fill p shifted (9cm,0) withcolor .7[red,white] ; +\stopbuffer + +\typebuffer[mp] + +\startlinecorrection[blank] +\processMPbuffer[mp] +\stoplinecorrection + +\startbuffer[mp] +vardef SampleText (expr t, c) = + save p ; picture p ; + p := image (draw t infont "\truefontname{Regular}") ; + draw (p shifted (- xpart center p,0)) scaled 5 withcolor c; +enddef ; + +SampleText ("Much Of This" , transparent(1, .5, red )) ; +SampleText ("Functionality" , transparent(1, .5, green)) ; +SampleText ("Was Written" , transparent(1, .5, blue )) ; +SampleText ("While Listening", transparent(1, .5, cmyk(1,0,0,0))) ; +SampleText ("To the CD's Of" , transparent(1, .5, cmyk(0,1,0,0))) ; +SampleText ("Tori Amos" , transparent(1, .5, cmyk(0,0,1,0))) ; +\stopbuffer + +So far we have applied transparent colors to shapes but text can also be the +target. + +\typebuffer[mp] + +The source code of this example illustrates that the \CMYK\ color space is also +supported. The \type {\truefontname} macro communicates the running font from +\TEX\ to \METAPOST. Instead of such low level code one can of course also use the +\type {textext} macro. + +\startbuffer[mp] +vardef SampleText (expr t) = + draw textext(t) scaled 5 ; +enddef ; + +SampleText ("\colored[a=1,t=.5,r=1]{Much Of This}") ; +SampleText ("\colored[a=1,t=.5,g=1]{Functionality}") ; +SampleText ("\colored[a=1,t=.5,b=1]{Was Written}") ; +SampleText ("\colored[a=1,t=.5,c=1]{While Listening}") ; +SampleText ("\colored[a=1,t=.5,m=1]{To the CD's Of}") ; +SampleText ("\colored[a=1,t=.5,y=1]{Tori Amos}") ; +\stopbuffer + +However, as we do the typesetting in \TEX\ in \MKIV\ this is the way to go: + +\typebuffer[mp] + +As expected we get: + +\startlinecorrection[blank] +\processMPbuffer[mp] +\stoplinecorrection + +Currently the 12 in \PDF\ available transparency methods are supported. \footnote +{In the future we may also support more control over the individual methods.} You +can use both numbers and names. As you may expect, both \CONTEXT\ and \METAFUN\ +support transparency in the same way. \in {Figure} [fig:transparencies] shows how +the method affects the result. + +\startuseMPgraphic{test} +numeric u ; u := if lua.mp.mode("screen") : 12mm else : 20mm fi ; + +path p ; p := fullcircle scaled u shifted (u/4,0); + +% cmykcolor xyellow ; xyellow := (0,0,1,0) ; +% color xgreen ; xgreen := (0,1,0) ; +% color xblue ; xblue := (0,0,1) ; + +% fill p rotated 90 withcolor transparent("\MPvar{a}",.5,xyellow) ; +% fill p rotated 210 withcolor transparent("\MPvar{a}",.5,xgreen) ; +% fill p rotated 330 withcolor transparent("\MPvar{a}",.5,xblue) ; + +fill p rotated 90 withcolor (0,0,1,0) withtransparency("\MPvar{a}",.5) ; +fill p rotated 210 withcolor (0,1,0) withtransparency("\MPvar{a}",.5) ; +fill p rotated 330 withcolor (0,0,1) withtransparency("\MPvar{a}",.5) ; +\stopuseMPgraphic + +\startplacefigure[location=here,reference=fig:transparencies,title={The 12 transparency alternatives by name.}] + \doifelsemode {screen} { + \setupcombination[nx=8,ny=2] + } { + \setupcombination[nx=4,ny=4] + } + \startcombination + {\useMPgraphic{test}{a=normal}} {\tttf normal} + {\useMPgraphic{test}{a=multiply}} {\tttf multiply} + {\useMPgraphic{test}{a=screen}} {\tttf screen} + {\useMPgraphic{test}{a=overlay}} {\tttf overlay} + {\useMPgraphic{test}{a=softlight}} {\tttf softlight} + {\useMPgraphic{test}{a=hardlight}} {\tttf hardlight} + {\useMPgraphic{test}{a=colordodge}} {\tttf colordodge} + {\useMPgraphic{test}{a=colorburn}} {\tttf colorburn} + {\useMPgraphic{test}{a=darken}} {\tttf darken} + {\useMPgraphic{test}{a=lighten}} {\tttf lighten} + {\useMPgraphic{test}{a=difference}} {\tttf difference} + {\useMPgraphic{test}{a=exclusion}} {\tttf exclusion} + {\useMPgraphic{test}{a=hue}} {\tttf hue} + {\useMPgraphic{test}{a=saturation}} {\tttf saturation} + {\useMPgraphic{test}{a=color}} {\tttf color} + {\useMPgraphic{test}{a=luminosity}} {\tttf luminosity} + \stopcombination +\stopplacefigure + +In \CONTEXT\ a transparent color is defined in a similar way as \quote {normal} +colors. The transparency method is specified with the \type {a} key (either by +number or by name) and the factor \type {t}. + +\startbuffer +\definecolor [tred] [r=1,t=.5,a=exclusion] +\definecolor [tgreen] [g=1,t=.5,a=exclusion] +\definecolor [tblue] [b=1,t=.5,a=exclusion] +\stopbuffer + +\typebuffer \getbuffer + +Both keys are needed. You can define your own symbolic names using: + +\starttyping +\definetransparency [myowndefault] [1] +\stoptyping + +The \type {\MPcolor} macro passes a color from \CONTEXT\ to \METAPOST, including +the transparency specification. + +\startbuffer[mp] +u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0); + +fill p rotated 90 withcolor \MPcolor{tred} ; +fill p rotated 210 withcolor \MPcolor{tgreen} ; +fill p rotated 330 withcolor \MPcolor{tblue} ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer[mp] +\stoplinecorrection + +Of course this also works well for \CMYK\ colors. + +\startbuffer +\definecolor[tred] [c=1,k=.2,t=.5,a=1] +\definecolor[tgreen][m=1,k=.2,t=.5,a=1] +\definecolor[tblue] [y=1,k=.2,t=.5,a=1] +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer[mp] +\stoplinecorrection + +Gray scales work as well: + +\startbuffer +\definecolor[ta][s=.9,t=.7,a=11] +\definecolor[tb][s=.7,t=.7,a=11] +\definecolor[tc][s=.5,t=.7,a=11] +\stopbuffer + +\typebuffer \getbuffer + +We apply this to some text. By using an overlay we can conveniently explore the +difference in fonts. + +% \startbuffer +% def SampleText (expr s, f, c) = +% draw s infont f scaled 5 withcolor c ; +% enddef ; + +% SampleText("Hello", "\truefontname{Regular}" , \MPcolor{ta}) ; +% SampleText("Hello", "\truefontname{RegularBold}" , \MPcolor{tb}) ; +% SampleText("Hello", "\truefontname{RegularSlanted}", \MPcolor{tc}) ; +% \stopbuffer + +\startbuffer +draw textext("\color[ta]{\tf Hello}") scaled 5 ; +draw textext("\color[tb]{\bf Hello}") scaled 5 ; +draw textext("\color[tc]{\sl Hello}") scaled 5 ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Shading}] + +\startsubsection[title=Introduction] + +\index{shading} + +In this section we introduce different kinds of shading. Since \METAPOST\ does +not support this feature directly, we have to fall back on a few tricks. For the +moment shading is only supported in \PDF. In the following examples, we will use +the next three colors: + +\startbuffer +\definecolor[a][darkyellow] +\definecolor[b][s=.8] +\definecolor[c][darkred] +\stopbuffer + +\typebuffer + +\getbuffer + +Shading support evolved in steps and alongside development of the backend code. Also, +as it became more used a second interface came available. We discuss both here. + +\stopsubsection + +\startsubsection[title=The old method] + +First we discuss the old method which is still valid and also available in +\MKII. It illustrates some of the principles. + +\startbuffer[a] +\startuniqueMPgraphic{CircularShade} + path p ; + p := unitsquare xscaled \overlaywidth yscaled \overlayheight ; + circular_shade(p,0,\MPcolor{a},\MPcolor{b}) ; +\stopuniqueMPgraphic + +\startuniqueMPgraphic{LinearShade} + path p ; + p := unitsquare xscaled \overlaywidth yscaled \overlayheight ; + linear_shade(p,0,\MPcolor{a},\MPcolor{b}); +\stopuniqueMPgraphic +\stopbuffer + +\startbuffer[b] +\defineoverlay[circular shade][\uniqueMPgraphic{CircularShade}] +\defineoverlay[linear shade] [\uniqueMPgraphic{LinearShade}] +\stopbuffer + +\startbuffer[c] +\framed + [background=circular shade,frame=off] + {\bf \white Hi there, I'm Circular!} +\stopbuffer + +\startbuffer[d] +\framed + [background=linear shade,frame=off] + {\bf \white Whow, this is Linear!} +\stopbuffer + +A shade is a fill with a stepwise change in color. In \POSTSCRIPT\ (level 2), the +way this color changes can be circular, linear, or according to a user defined +function. Circular and linear shades look like this: + +\startlinecorrection[blank] +\getbuffer[a,b,c] +\stoplinecorrection + +\startlinecorrection[blank] +\getbuffer[a,b,d] +\stoplinecorrection + +As you can see, the shade lays behind the text, as a background overlay. These +overlays are unique \METAPOST\ graphics, so they will adapt themselves to the +dimensions of the foreground. + +\typebuffer[b] + +The two framed texts are defined as: + +\typebuffer[c] + +and: + +\typebuffer[d] + +We still have to define the graphics. Here we use a macro that takes four +arguments: a path, a number identifying the center of shading, and the colors to +start and end with. + +\typebuffer[a] + +The \METAPOST\ macros, \type {circular_shade} and \type {linear_shade}, add +information to the \METAPOST\ output file, which is interpreted by the converter +built in \CONTEXT. Shading comes down to interpolation between two or more points +or user supplied ranges. A poor mans way of doing this, is to build the graphics +piecewise with slightly changing colors. But, instead of \quote {manually} +stepping through the color values, we can use the more efficient and generalized +\POSTSCRIPT\ level~2 and \PDF\ level~1.3 shading feature. + +\def\SomeShade#1#2#3% waarom unique ? + {\startuniqueMPgraphic{shade-#1} + width := \overlaywidth ; + height := \overlayheight ; + path p ; p := unitsquare xscaled width yscaled height ; + #2_shade(p,#3,\MPcolor{a},\MPcolor{b}) ; + \stopuniqueMPgraphic + \defineoverlay[shade-#1][\uniqueMPgraphic{shade-#1}]% + \framed[background=shade-#1,width=2cm,height=2cm,frame=off]{}} + +\startlinecorrection[blank] +\startcombination[5*1] + {\SomeShade{20}{circular}{0}} {circular 0} + {\SomeShade{21}{circular}{1}} {circular 1} + {\SomeShade{22}{circular}{2}} {circular 2} + {\SomeShade{23}{circular}{3}} {circular 3} + {\SomeShade{24}{circular}{4}} {circular 4} +\stopcombination +\stoplinecorrection + +\startlinecorrection[blank] +\startcombination[4*2] + {\SomeShade{32}{linear}{1}} {linear 1} + {\SomeShade{32}{linear}{2}} {linear 2} + {\SomeShade{33}{linear}{3}} {linear 3} + {\SomeShade{34}{linear}{4}} {linear 4} + {\SomeShade{35}{linear}{5}} {linear 5} + {\SomeShade{36}{linear}{6}} {linear 6} + {\SomeShade{37}{linear}{7}} {linear 7} + {\SomeShade{38}{linear}{8}} {linear 8} +\stopcombination +\stoplinecorrection + +% % This limitation si no longer present in mpiv. +% +% Shading is not a \METAPOST\ feature, which means that it has to be implemented +% using so called specials, directives that end up in the output file. +% Unfortunately these are not coupled to the specific path, which means that we +% have to do a significant amount of internal bookkeeping. Also, in \PDF\ we have +% to make sure that the graphics and their resources (being the shading functions) +% are packaged together. +% +% Because of this implementation, shading may behave somewhat unexpected at times. +% A rather normal case is the next one, where we place 5~shaded circles in a row. +% +% \startbuffer +% path p ; p := fullcircle scaled 1cm ; +% for i=0 step 2cm until 8cm : +% circular_shade(p shifted (i,0),0,\MPcolor{a},\MPcolor{b}) ; +% endfor ; +% \stopbuffer +% +% \typebuffer +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% At first sight, in the next situation, we would expect something similar, because +% we simply copy the same circle 5~times. However, due to the way we have +% implemented shading in \CONTEXT, we do indeed copy the circles, but the shade +% definition is frozen and the same one is used for all 5~circles. This means that +% the center of the shading stays at the first circle. +% +% \startbuffer +% circular_shade(fullcircle scaled 1cm,0,\MPcolor{a},\MPcolor{b}) ; +% picture s ; s := currentpicture ; currentpicture := nullpicture ; +% for i=0 step 2cm until 8cm : +% addto currentpicture also s shifted (i,0) ; +% endfor ; +% \stopbuffer +% +% \typebuffer +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% Unlike \TEX, \METAPOST\ does not keep its specials attached to the current path, +% and flushes them before the graphic data. Since we use these specials to register +% shading information, it is rather hard to tightly connect a specific shade with a +% certain fill, especially if an already performed fill is not accessible, which is +% the case when we copy a picture. +% +% This may seem a disadvantage, but fortunately it also has its positive side. In +% the next example we don't copy, but reuse an already defined shade. By storing +% the reference to this shade, and referring to it by using \type {withshade}, we +% can use a shade that operates on multiple shapes. + +\startbuffer +sh := define_circular_shade + (origin,origin,0,8cm,\MPcolor{a},\MPcolor{b}) ; +for i=0 step 2cm until 8cm : + fill fullcircle scaled 1cm shifted (i,0) withshade sh ; +endfor ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The low level macro \type {define_circular_shade} is fed with two pairs (points), +two radius, and two colors. The shade is distributed between the colors according +to the radius. + +Shading can hardly be called an easy issue. The macros that we provide here are +in fact simplifications, which means that at a lower level, one can do more +advanced things. Here we limit ourselves to the more common cases. In the +previous examples, we used an arrow to indicate the direction and magnitude of +the shade. The next macro demonstrates the principles in a different way. + +\startbuffer[a] +def test_shade (expr a, b, ra, rb) = + pickup pencircle scaled 1mm ; + + color ca ; ca := \MPcolor{a} ; + color cb ; cb := \MPcolor{b} ; + color cc ; cc := \MPcolor{c} ; + + path pa ; pa := fullcircle scaled 2ra shifted a ; + path pb ; pb := fullcircle scaled 2rb shifted b ; + + sh := define_circular_shade(a,b,ra,rb,ca,cb) ; + + fill pb withshade sh ; + draw pb withcolor cc ; + draw pa withcolor cc ; +enddef ; +\stopbuffer + +\typebuffer[a] + +The shade is distributed between two circles, each with a radius and center +point. All four can be set, but as the next calls demonstrate, we can normally do +with less, which is why we provided the macro with less parameters. + +\startbuffer[b] +test_shade(origin, origin, 0cm, 1cm) ; +\stopbuffer +\startbuffer[c] +test_shade(origin, origin, .25cm, 1cm) ; +\stopbuffer +\startbuffer[d] +test_shade(origin, origin, .50cm, 1cm) ; +\stopbuffer + +\startbuffer[f] +\startlinecorrection[blank] +\hbox + {\processMPbuffer[a,b]\quad + \processMPbuffer[a,c]\quad + \processMPbuffer[a,d]} +\stoplinecorrection +\stopbuffer + +\typebuffer[b,c,d] \getbuffer[f] + +\startbuffer[b] +test_shade(origin, origin shifted (.25cm,0), 0cm, 1cm) ; +\stopbuffer +\startbuffer[c] +test_shade(origin, origin shifted (.25cm,0), .25cm, 1cm) ; +\stopbuffer +\startbuffer[d] +test_shade(origin, origin shifted (.25cm,0), .50cm, 1cm) ; +\stopbuffer + +\typebuffer[b,c,d] \getbuffer[f] + +\startbuffer[b] +test_shade(origin shifted (.25cm,0), origin, 0cm, 1cm) ; +\stopbuffer +\startbuffer[c] +test_shade(origin shifted (.25cm,0), origin, .25cm, 1cm) ; +\stopbuffer +\startbuffer[d] +test_shade(origin shifted (.25cm,0), origin, .50cm, 1cm) ; +\stopbuffer + +\typebuffer[b,c,d] \getbuffer[f] + +\startbuffer[a] +def test_shade (expr a, b) = + pickup pencircle scaled 1mm ; + + color ca ; ca := \MPcolor{a} ; + color cb ; cb := \MPcolor{b} ; + color cc ; cc := \MPcolor{c} ; + + sh := define_linear_shade(a,b,ca,cb) ; + + fill fullsquare scaled 2cm withshade sh ; + draw a withcolor cc ; + draw b withcolor cc ; +enddef ; +\stopbuffer + +In a similar fashion, we can define a linear shade. This time we only pass two +points and two colors. + +\typebuffer[a] + +Although one can control shading to a large extend, in practice only a few cases +really make sense. + +\startbuffer[b] +test_shade(origin, origin shifted (1cm,0)) ; +\stopbuffer +\startbuffer[c] +test_shade(origin shifted (-1cm,0), origin shifted (1cm,0)) ; +\stopbuffer +\startbuffer[d] +test_shade(origin shifted (-1cm,-1cm), origin shifted (1cm,1cm)) ; +\stopbuffer + +\startbuffer[f] +\startlinecorrection[blank] +\hbox + {\processMPbuffer[a,b]\quad + \processMPbuffer[a,c]\quad + \processMPbuffer[a,d]} +\stoplinecorrection +\stopbuffer + +\typebuffer[b,c,d] \getbuffer[f] + +\stopsubsection + +\startsubsection[title=The new method] + +By now the shader macros are rather advanced and specifications are easier than +before. Here we discuss the new method. An example is: + +\startbuffer +fill fullsquare xyscaled (TextWidth,1cm) + withshademethod "linear" + withshadevector (1,0) + withshadecolors (darkred,darkgreen) +; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +There are several properties that can be set: + +\starttabulate[|l|p|] +\NC domain \NC The range over which the colors run, with a minimum of 0 and maximum of 1. \NC \NR +\NC color \NC A color to start from and one to end with, we default from black to white. \NC \NR +\NC type \NC The shading can be linear or circular. \NC \NR +\NC center \NC The origin of the shade vector. \NC \NR +\NC radius \NC The radius vector of a circular shade. \NC \NR +\NC vector \NC Where we start and end the shading. \NC \NR +\stoptabulate + +For a linear shade the centers are the lower left and upper right corners, for a +circular shade it's the center of the path. For a circular shade the radius runs +from zero to the maximum distance from the center as determined by the +boundingbox. + +The vector is used as follows: the first coordinate (xpart) determines the point +on the path where we start, the second coordinate (ypart) the point on the +path where we end. + +\startbuffer[a] +fill fullsquare xyscaled (TextWidth,1cm) + withshademethod "linear" + withshadevector (1,0) + withshadecolors (darkred,darkgreen) +; +\stopbuffer + +\startbuffer[b] +draw fullsquare xyscaled (TextWidth,1cm) + shownshadevector (1,0) + withpen pencircle scaled 2 + withcolor .5white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +In the end only the x coordinate matters, but using a point on the path sort of +fits in \METAPOST. In the case of a rectangle we have 4 points while circle has 8 +points. + +\startbuffer[a] +fill fullcircle xyscaled (TextWidth,1cm) + withshademethod "linear" + withshadevector (2,4) + withshadecolors (darkred,darkgreen) +; +\stopbuffer + +\startbuffer[b] +draw fullcircle xyscaled (TextWidth,1cm) + shownshadevector (2,4) + withpen pencircle scaled 2 + withcolor .5white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +A triangle has three points. Using 1 and 2 as second vector value gives the same +results as do values in the range 0 upto 1 and 2 upto 3 (0 again). + +\startbuffer[a] +fill fulltriangle xyscaled (TextWidth,1cm) + withshademethod "linear" + withshadevector (0.25,0.75) + withshadecolors (darkred,darkgreen) +; +\stopbuffer + +\startbuffer[b] +draw fulltriangle xyscaled (TextWidth,1cm) + shownshadevector (0.25,0.75) + withpen pencircle scaled 2 + withcolor .5white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +The shadevector relates to (the x coordinates of) points on the path. A variant is +to use the boundingbox: + +\startbuffer[a] +for i=1 upto 3 : + fill fulltriangle xyscaled (TextWidth,1cm) + shifted (0,-i*15mm) + withshademethod "linear" + withshadedirection (1,1-i/4) + withshadecolors (darkgreen,darkblue) + ; +endfor ; +\stopbuffer + +\startbuffer[b] +for i=1 upto 3 : + draw fulltriangle xyscaled (TextWidth,1cm) + shifted (0,-i*15mm) + shownshadevector (1,1-i/4) + withpen pencircle scaled 2 + withcolor .5white ; +endfor ; +\stopbuffer + +\typebuffer[a] + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +So, where a vector is defined as going from {\em point xpart a of pth} to +{\em point ypart a of pth}, a direction goes from {\em point xpart a of +boundingbox pth} to {\em point ypart a of boundingbox pth}. + +To make life convenient we provide a few constants that indicate directions: + +\starttyping +pair shadedup ; shadedup := (0.5,2.5) ; +pair shadeddown ; shadeddown := (2.5,0.5) ; +pair shadedleft ; shadedleft := (1.5,3.5) ; +pair shadedright ; shadedright := (3.5,1.5) ; +\stoptyping + +\startbuffer[a] +for d = shadedup, shadeddown, shadedleft, shadedright : + fill fullsquare xyscaled (TextWidth,1cm) + withshademethod "linear" + withshadedirection d + withshadecolors (darkgreen,darkblue) + ; + currentpicture := currentpicture shifted (0,15mm) ; +endfor ; +\stopbuffer + +\startbuffer[b] +currentpicture := currentpicture shifted (0,-60mm) ; +for d = shadedup, shadeddown, shadedleft, shadedright : + draw fullsquare xyscaled (TextWidth,1cm) + shownshadedirection d + withpen pencircle scaled 2 + withcolor .5white ; + currentpicture := currentpicture shifted (0,15mm) ; +endfor ; +\stopbuffer + +\typebuffer[a] + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +In case of a circular shade another method comes in handy: + +\startbuffer[a] +fill fullcircle xyscaled (TextWidth,4cm) + withshademethod "circular" + withshadecenter (.7,.9) + withshadecolors (darkblue,darkyellow) +; +\stopbuffer + +\startbuffer[b] +draw fullcircle xyscaled (TextWidth,4cm) + shownshadecenter (.7,.9) + withpen pencircle scaled 2 + withcolor .5white ; +\stopbuffer + +\typebuffer + +Here the values relate to the center of path i.e.\ they shift the center by the +given fraction of the width and height of the boundingbox devided by 2. + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +You can set a center directly i.e.\ unrelated to the center of the path as +follows: + +\startbuffer[a] +fill fullcircle xyscaled (TextWidth,4cm) + withshademethod "circular" + withshadeorigin (-30mm,-15mm) + withshadecolors (darkblue,darkyellow) +; +\stopbuffer + +\startbuffer[b] +draw fullcircle xyscaled (TextWidth,4cm) + shownshadeorigin (-30mm,-15mm) + withpen pencircle scaled 2 + withcolor .5white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer[a,b] +\stoplinecorrection + +In a similar way you can set an explicit radius: + +\startbuffer[a] +fill fullcircle xyscaled (TextWidth,1cm) + withshademethod "circular" + withshaderadius (10mm,50mm) + withshadecolors (darkblue,darkyellow) +; +currentpicture := currentpicture shifted (0,15mm) ; +fill fullcircle xyscaled (TextWidth,1cm) + withshademethod "circular" + withshaderadius (50mm,10mm) + withshadecolors (darkgreen,darkred) +; +currentpicture := currentpicture shifted (0,15mm) ; +fill fullcircle xyscaled (TextWidth,1cm) + withshademethod "circular" + withshaderadius (TextWidth/3,0mm) + withshadecolors (darkmagenta,darkcyan) +; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer[a] +\stoplinecorrection + +A more fancy feature is combined shades. This works as follows: + +\startbuffer[a] +fill fullsquare xyscaled (TextWidth,1cm) + withshademethod "linear" + withshadevector (0,1) + withshadestep ( + withshadefraction .3 + withshadecolors (red,green) + ) + withshadestep ( + withshadefraction .5 + withshadecolors (green,blue) + ) + withshadestep ( + withshadefraction .7 + withshadecolors (blue,red) + ) + withshadestep ( + withshadefraction 1 + withshadecolors (red,yellow) + ) +; +\stopbuffer + +\typebuffer[a] + +By stepwise defining the colored bands you get: + +\startlinecorrection[blank] + \processMPbuffer[a] +\stoplinecorrection + +Shades work well with colors and transparencies. This involves quite some +resource managament in the backend but it's hidden by the interface. + +\startbuffer[a] +fill fullsquare scaled 5cm + withshademethod "linear" + withshadefactor 1 + withshadedomain (0,1) + withshadevector (0.5,2.75) + withshadecolors (red,green) ; + +fill fullcircle scaled 5cm + withshademethod "circular" + withshadefactor 1 + withshadedomain (0,1) + withshadecenter (.25,.25) + withshadecolors (green,blue) ; + +fill fulltriangle scaled 5cm + withshademethod "circular" + withshadefactor 1 + withshadedomain (0,1) + withshadecenter (.25,.25) + withshadecolors (blue,yellow) ; +\stopbuffer + +\startbuffer[b] +fill fullsquare scaled 5cm + withcolor white ; +fill fullsquare scaled 5cm + withshademethod "linear" + withshadevector (0.5,2.75) + withshadecolors (red,green) + withtransparency (1,.5) ; + +fill fullcircle scaled 5cm + withcolor white ; +fill fullcircle scaled 5cm + withshademethod "circular" + withshadecenter (.25,.25) + withshadecolors (green,blue) + withtransparency (1,.5) ; + +fill fulltriangle scaled 5cm + withcolor white ; +fill fulltriangle scaled 5cm + withshademethod "circular" + withshadecenter (.25,.25) + withcolor blue shadedinto yellow + withtransparency (1,.5) ; +\stopbuffer + +\startbuffer[c] +fill fullsquare scaled 5cm + withshademethod "linear" + withshadevector (0.5,2.75) + withshadecolors (red,green) + withtransparency (1,.5) ; + +fill fullcircle scaled 5cm + withshademethod "circular" + withshadecenter (.25,.25) + withcolor green shadedinto blue + withtransparency (1,.5) ; + +fill fulltriangle scaled 5cm + withshademethod "circular" + withshadecenter (.25,.25) + withcolor blue shadedinto yellow + withtransparency (1,.5) ; +\stopbuffer + +Here are some shades without transparency: + +\typebuffer[a] + +When the background is white, transparency is just a way to achieve soft colors. +We leave out the defaults. + +\typebuffer[b] + +Real transparency will show op darker due to the accumulated colors. This time we +demonstrate an alternative color specification. + +\typebuffer[c] + +\startplacefigure[reference=shades:transparency,title={Transparency applied to shades.}] + \startcombination[3*1] + {\processMPbuffer[a]} {no transparency} + {\processMPbuffer[b]} {transparency on white} + {\processMPbuffer[c]} {real transparency} + \stopcombination +\stopplacefigure + +Within reasonable bounds you can move around and adapt shaded paths but you need +to keep in mind that due to the fact that we are dealing with relatively complex +data structures there are some limits. For instance it is possible to define a +shade as (kind of) variable and reuse it. it's also possible then to overload +some properties. + +% % still supported but not advertized: +% +% numeric n ; n = define_linear_shade (center fullcircle,center fullsquare,red,green) ; +% +% fill fullcircle randomized 1cm xyscaled(10cm,8cm) withshade n ; + +\startbuffer +defineshade myshade + withshademethod "circular" + withshadefactor 1 + withshadedomain (0,1) + withshadecolors (black,white) + withtransparency (1,.5) +; + +for i=1 upto 5 : + fill fullcircle randomized 1 xyscaled(5cm,3cm) + shaded myshade ; +endfor ; + +draw image ( + for i=1 upto 5 : + fill fullcircle randomized 1 + shaded myshade + withshadecolors (yellow,blue) ; + endfor ; +) xyscaled(5cm,3cm) shifted (5cm,0) ; +\stopbuffer + +\typebuffer + +We get two groups of five overlayed shades here, one with a different color. The +shade properties can only be applied to paths (see \in {figure} +[fig:shades:defined]). + +\startplacefigure[reference=fig:shades:defined,title={Reusing defined shaded.}] + \processMPbuffer +\stopplacefigure + +In older versions one could not reposition or scale a shaded path without losing +or crippling the shade properties. Nowadays this is no longer a limitation, as we +demonstrate in the following examples. You can disable this feature if wanted. +The results are shown in \in {figure} [fig:shades:transform]. Without the +transform the vectors and such are kept which might be useful in special cases. + +\startbuffer[a] +fill fullsquare xyscaled (15mm, 15mm) + withshademethod "linear" + withshadedirection shadedright + withshadecolors (red,(1,1,1)) ; + +fill fullsquare xyscaled (10mm, 10mm) + withshademethod "circular" + withshadecolors (green,blue) ; + +currentpicture := currentpicture xysized (.4TextWidth,30mm) ; +currentpicture := currentpicture shifted (5mm,5mm) ; +\stopbuffer + +\typebuffer[a] + +The transform can be ignored with: + +\startbuffer[b] +fill fullsquare xyscaled (15mm, 15mm) + withshademethod "linear" + withshadetransform "no" + withshadedirection shadedright + withshadecolors (red,(1,1,1)) ; + +fill fullsquare xyscaled (10mm, 10mm) + withshademethod "circular" + withshadetransform "no" + withshadecolors (green,blue) ; + +currentpicture := currentpicture xysized (.4TextWidth,30mm) ; +currentpicture := currentpicture shifted (5mm,5mm) ; +\stopbuffer + +\typebuffer[b] + +\startplacefigure[reference=fig:shades:transform,title={Shifting and scaling shades.}] + \startcombination + {\processMPbuffer[a]} {with transform} + {\processMPbuffer[b]} {without transform} + \stopcombination +\stopplacefigure + +\stopsubsection + +\stopsection + +\startsection[title={Clipping}] + +\index{clipping} + +In this section we will use the graphic representation (although simplified) of a +Dutch cow to demonstrate clipping. + +\startbuffer +\placefigure + {A cow.} + {\externalfigure[cow-fun.mps][width=4cm]} +\stopbuffer + +\getbuffer + +Since this cow is defined as a \METAPOST\ graphic, we use the suffix \type {mps} +instead of \type {eps} or a number, although \CONTEXT\ will recognize each as +being \METAPOST\ output. The placement of the cow is defined as: + +\typebuffer + +Clipping is combined with a matrix, as in \in {figure} [fig:clipped cow 1]. The +content to be clipped is divided in \type {nx} by \type {ny} rectangles. For +instance, \type {nx=5} and \type {ny=8} will produce a 40~cell grid with +5~columns of 8~rows. + +\startbuffer +\startbuffer +\setupclipping[nx=3,ny=2] +\startcombination + {\clip[x=1,y=1]{\externalfigure[cow-fun.mps][width=4cm]}} {1,1} + {\clip[x=3,y=1]{\externalfigure[cow-fun.mps][width=4cm]}} {3,1} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:clipped cow 1] + {A clipped cow.}{\getbuffer} +\stopbuffer + +\getbuffer + +Here we have divided the cow in six cells, so that we can clip its head and tail. +This kind of clipping enables you to zoom in or focus on a specific part of a +graphic. + +\typebuffer + +Alternatively, we can specify a \type {width}, \type {height}, \type {hoffset} +and \type {voffset}, as demonstrated in \in {figure} [fig:clipped cow 2]. + +\startbuffer +\placefigure + [here][fig:clipped cow 2] + {Another clipped cow.} + {\clip + [width=2cm,height=2cm,hoffset=0cm,voffset=0cm] + {\externalfigure[cow-fun.mps][width=4cm]}} +\stopbuffer + +\getbuffer + +\typebuffer + +Because \METAPOST\ supports clipping, it will be no surprise that both techniques +can be combined. In the next example we will zoom in on the head of the cow. We +also use this opportunity to demonstrate how you can package a clip in a figure +definition. + +\startbuffer +\startMPclip{head clip} + w := \width ; h := \height ; + clip currentpicture to + ((0,h)--(w,h){down}..{left}(0,0)--cycle) ; +\stopMPclip + +\placefigure + [here][fig:circular clipped cowhead] + {A quarter circle applied to a cows head.} + {\ruledhbox + {\clip + [nx=2,ny=2,x=1,y=1,mp=head clip] + {\externalfigure[cow-fun.mps][width=4cm]}}} +\stopbuffer + +\typebuffer + +A more advanced clip is demonstrated in \in {figure} [fig:circular clipped +cowhead]. We added \type {\ruledhbox} to demonstrate the dimensions of the +resulting graphic. Putting something in such a ruled box is often a quick way to +test spacing. + +\getbuffer + +Although a clip path definition can contain any \METAPOST\ command, even +graphics, it must contain at least one clipping path. The first one encountered +in the resulting graphic is used. In the example we used a path that is built out +of three subpaths. + +\starttyping +(0,h)--(w,h){down}..{left}(0,0)--cycle +\stoptyping + +We start in the top left corner and draw a straight line. Next we draw a curve to +the origin. Directives like \type {down} and \type {right} force the curve in a +certain direction. With \type {cycle} we close the path. Because we use this path +as a clipping path, we use \type {clip} instead of \type {draw} or \type {fill}. + +\startbuffer +w := 4cm ; h := 2cm ; +draw (0,h)--(w,h){down}..{left}(0,0)--cycle + withpen pencircle scaled 1mm withcolor .625red ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Clipping as such is not limited to graphics. Take for instance the text buffer: + +\startbuffer +\startbuffer[sample] +\framed + [align=middle,width=4cm,background=screen,frame=off] + {A \METAPOST\ clip is not the same as a video clip, + although we can use \METAPOST\ to produce a video clip.} +\stopbuffer +\stopbuffer + +\typebuffer + +\getbuffer + +We can call up such a buffer as if it were an external figure. \in {Figure} +[fig:clipped text 1] shows the result. This time we use a different clip path: + +\startbuffer[a] +\startMPclip{text clip} + clip currentpicture to fullcircle shifted (.5,.5) + xscaled \width yscaled \height ; +\stopMPclip +\stopbuffer + +\typebuffer[a] + +To load a buffer, we have to specify its name and type, as in: + +\startbuffer[b] +\placefigure + [here][fig:clipped text 1] + {A clipped buffer (text).} + {\clip + [nx=1,ny=1,mp=text clip] + {\externalfigure[sample][type=buffer,width=4cm]}} +\stopbuffer + +\typebuffer[b] + +\getbuffer[a,b] + +The next few lines demonstrate that we can combine techniques like backgrounds +and clipping. + +\startbuffer +\startuseMPgraphic{clip outline} + draw fullcircle + xscaled \overlaywidth yscaled \overlayheight + withpen pencircle scaled 4mm + withcolor .625red ; +\stopuseMPgraphic + +\defineoverlay[clip outline][\useMPgraphic{clip outline}] + +\placefigure + [here][fig:clipped text 2] + {A clipped buffer (text).} + {\framed + [background=clip outline,offset=overlay,frame=off] + {\clip + [nx=1,ny=1,mp=text clip] + {\externalfigure[sample][type=buffer,width=4cm]}}} +\stopbuffer + +\typebuffer + +We could have avoided the \type {\framed} here, by using the \typ{clip outline} +overlay as a background of the sample. In that case, the resulting linewidth +would have been 2.5~mm instead of 5~mm, since the clipping path goes through the +center of the line. + +\getbuffer + +In most cases, the clip path will be a rather simple path and defining such a +path every time you need it, can be annoying. \in {Figure} [fig:clipping paths] +shows a collection of predefined clipping paths. These are available after +loading the \METAPOST\ clipping library. + +\starttyping +\useMPlibrary[clp] +\stoptyping + +We already saw how the circular clipping path was defined. The diamond is defined +in a similar way, using the predefined path \type {diamond}: + +\starttyping +\startMPclip{diamond} + clip currentpicture to unitdiamond + xscaled \width yscaled \height ; +\stopMPclip +\stoptyping + +The definition of the negated ellipse (\type {negellipse}) uses the primary \type +{peepholed}. This primary is defined in one of the \METAPOST\ modules that come +with \CONTEXT. + +\starttyping +\startMPclip{negellipse} + clip currentpicture to (unitcircle peepholed unitsquare) + xscaled \width yscaled \height ; +\stopMPclip +\stoptyping + +The definition of \type {peepholed} is rather dirty and using \type {peepholed} +is restricted to well defined situations (like here). It's called a primary +because it acts as an operator at the same level as \type {*} and \type {scaled}. + +\startbuffer +\setupclipping [nx=1,ny=1,x=1,y=1] +\setupblackrules[width=2cm,height=1cm] +\startcombination[6*3] + {\clip[mp=urellipse] {\darkred\blackrule}} {urellipse} + {\clip[mp=ulellipse] {\darkred\blackrule}} {ulellipse} + {\clip[mp=llellipse] {\darkred\blackrule}} {llellipse} + {\clip[mp=lrellipse] {\darkred\blackrule}} {lrellipse} + {\clip[mp=ellipse] {\darkred\blackrule}} {ellipse} + {\clip[mp=negellipse]{\darkred\blackrule}} {negellipse} + {\clip[mp=tellipse] {\darkred\blackrule}} {tellipse} + {\clip[mp=bellipse] {\darkred\blackrule}} {bellipse} + {\clip[mp=lellipse] {\darkred\blackrule}} {lellipse} + {\clip[mp=rellipse] {\darkred\blackrule}} {rellipse} + {} {} + {} {} + {\clip[mp=urtriangle]{\darkred\blackrule}} {urtriangle} + {\clip[mp=ultriangle]{\darkred\blackrule}} {ultriangle} + {\clip[mp=lltriangle]{\darkred\blackrule}} {lltriangle} + {\clip[mp=lrtriangle]{\darkred\blackrule}} {lrtriangle} + {\clip[mp=diamond] {\darkred\blackrule}} {diamond} + {\clip[mp=negdiamond]{\darkred\blackrule}} {negdiamond} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:clipping paths] + {A collection of predefined clipping paths.} + {\getbuffer} + +\stopsection + +\startsection[title={Including graphics}] + +\index{graphics+including} + +This document demonstrates that it is no big problem to include \METAPOST\ +graphics in a \TEX\ document. But how about including graphics in a \METAPOST\ +picture? In this section we will explore a couple of macros that provide you this +feature. + +Before we go into details, we introduce a very impressive program called +\PSTOEDIT\ by Wolfgang Glunz. This program runs on top of \GHOSTSCRIPT\ and is +able to convert \POSTSCRIPT\ code into other formats, among them \METAPOST\ (that +part of the \PSTOEDIT\ code is due to Scott Pakin). Some of the graphics that we +use in this section are produced that way. For us, the next call works well, but +the exact call may differ per version or platform. + +\starttyping +pstoedit -ssp -dt -f mpost yourfile.ps newfile.mp +\stoptyping + +We have converted the Dutch cow that shows up in many \CONTEXT\ documents into +\METAPOST\ using this program. The resulting \METAPOST\ file encapsulates the cow +in \METAPOST\ figure~1: \type {beginfig(1)}. Of course you can process this file +like any other, but more interesting is to use this code in an indirect way. + +\startbuffer +loadfigure "mycow.mp" number 1 scaled .5 ; +\stopbuffer + +\typebuffer + +This call will load figure~1 from the specified \METAPOST\ file, in such a way +that there is no interference with the current (encapsulating) figure. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Because this graphic is the result from a conversion, there are only paths. If +you want to import a more complex graphic, you need to make sure that the +variables used in there do not conflict with the one currently in use. + +\METAPOST\ is good in drawing vector graphics, but lacks natural support for +bitmaps, but the next macro offers a way out. This macro permits you to include +graphics in \PNG, \PDF, and \JPG\ format, or more precise: those formats +supported by \PDFTEX.\pagereference[hacker] + +\startbuffer +draw externalfigure "hacker.png" scaled 5cm shifted (-6cm,0) ; +draw externalfigure "hacker.png" scaled 5cm slanted .5 ; +\stopbuffer + +\typebuffer + +You can apply the usual transformations, but only those applied directly will be +taken into account. This means that you (currently) cannot store external figures +in picture variables in order to transform them afterwards. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Although you are limited in what you can do with such graphics, you can include +them multiple times with a minimum of overhead. Graphics are stored in objects +and embedded only once. + +\startbuffer +numeric s ; pair d, c ; +for i := 1 upto 5 : + s := 3cm randomized 1cm ; % size of picture + c := .5(s,s) ; % center of picture + d := (2cm*i,.5cm) randomized .5cm ; % displacement + draw externalfigure "hacker.png" + scaled s rotatedaround (c,0 randomized 30) shifted d ; +endfor ; +\stopbuffer + +\typebuffer + +Because we cannot store the graphic in a picture and scale afterwards, we +calculate the scale in advance, so that we can rotate around the center. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +As long as you don't mess around with a stored external figure, you're safe. The +following example demonstrates how we can combine two special driven features: +figure inclusion and shading. + +\startbuffer +picture p ; +p := externalfigure "hacker.png" scaled 150pt ; +clip p to unitcircle scaled 150pt ; +circular_shade(boundingbox p enlarged 10pt, 0, .2red, .9red) ; +addto currentpicture also p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +We end this section with a few more words to \METAPOST\ inclusion. It may seem +that in order to use the features discussed here, you need to use \CONTEXT\ as +typesetting engine. This is not true. First of all, you can use the small \TEX\ +package \MPTOPDF\ (described in another manual) or you can make small \CONTEXT\ +files with one page graphics. The advantage of the last method is that you can +manipulate graphics a bit. + +\starttyping +\setupcolors[cmyk=yes,rgb=no,state=start] + +\starttext + +\startMPpage[offset=6pt] + loadfigure "niceone.mp" number 10 ; +\stopMPpage + +\stoptext +\stoptyping + +The resulting \PDF\ file can be included as any other graphic +and has the advantage that it is self contained. + +\stopsection + +\startsection[reference=sec:conversion,title={Changing colors}] + +\index{color+manipulating} + +One of the advantages of \METAPOST\ graphics is that it is rather easy to force +consistency in colors and line widths. You seldom can influence third party +graphics that way, but we can use some \METAFUN\ trickery to get around this +limitation. + +\startbuffer +loadfigure "mycow.mp" number 1 scaled .35 ; +refill currentpicture withcolor .625red ; +\stopbuffer + +Say that we want a red cow instead of a black one. The following code does the +trick: + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +In a similar way we can influence the width and colors of the lines. + +\startbuffer +loadfigure "mycow.mp" number 1 scaled .35 ; +refill currentpicture withcolor .625red ; +redraw currentpicture withpen pencircle scaled 2pt withcolor .625yellow ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Of course we can also use the more fancy features of \METAFUN, like transparency +and shading. + +\startbuffer +loadfigure "mycow.mp" number 1 scaled .35 ; +numeric sh ; sh := define_linear_shade + (llcorner currentpicture,urcorner currentpicture,.625red, .625yellow) ; +refill currentpicture withshade sh ; +redraw currentpicture withpen pencircle scaled 2pt withcolor .5white; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Before we show a next trick, we draw a few circles. + +\startbuffer[a] +fill fullcircle scaled 2cm withcolor yellow ; +fill fullcircle scaled 2cm shifted (3cm,0) withcolor red ; +\stopbuffer + +\typebuffer[a] + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +The yellow and red color do not match the main document colors, but this is no +problem: we can remap them, without spoiling the original definition. + +\startbuffer[b] +remapcolor(yellow,.625yellow) ; +remapcolor(red ,.625red) ; +recolor currentpicture ; +resetcolormap ; +\stopbuffer + +\typebuffer[a,b] + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +We can combine the inclusion technique with remapping colors. This time using an +artist impression of one of Hasselts Canals (gracht in Dutch)\pagereference +[canal]. + +\startbuffer[a] +loadfigure "gracht.mp" number 1 scaled .5 ; +\stopbuffer + +\typebuffer[a] + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +If you think that the sky is too bright in this picture, and given that you also +know which color is used, you can fool the reader by remapping a few colors. + +\startbuffer[b] +color skycolor ; skycolor := (0.8,0.90,1.0) ; +color watercolor ; watercolor := (0.9,0.95,1.0) ; +remapcolor(skycolor ,.8skycolor ) ; +remapcolor(watercolor,.8watercolor) ; +recolor currentpicture ; +resetcolormap ; +\stopbuffer + +\typebuffer[a,b] + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +Including another \METAPOST\ graphic, refilling, redrawing, and recoloring are +all relatively simple features that use no real tricks. Opposite to the next +feature, which is implemented using the \METAPOST\ special driver that comes with +\CONTEXT. + +\METAPOST\ is not really meant for manipulating graphics, but the previous +examples demonstrated that we have some control over individual colors. In the +next series of examples we will treat the picture as a whole. First we invert the +colors using \type {inverted}. + +\startbuffer +loadfigure "gracht.mp" number 1 scaled .5 ; +addto currentpicture also + inverted currentpicture + shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +This is a special case of \type {uncolored}. In the next example we explicitly +specify the color. + +\startbuffer +loadfigure "gracht.mp" number 1 scaled .5 ; +addto currentpicture also + (currentpicture uncolored green) + shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +You can also multiply each color using \type {softened}. In the next sample, the +colors have 80\% of their value. + +\startbuffer +loadfigure "gracht.mp" number 1 scaled .5 ; +addto currentpicture also + (currentpicture softened .8) + shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +You can also use this operator to harden colors, simply by +providing a value larger than~1. Keep in mind that colors +are clipped at~1 anyway. + +\startbuffer +loadfigure "gracht.mp" number 1 scaled .5 ; +addto currentpicture also + (currentpicture softened 1.2) + shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +By providing a triplet, you can treat each color component +independently. + +\startbuffer +loadfigure "gracht.mp" number 1 scaled .5 ; +addto currentpicture also + (currentpicture softened (.7,.8,.9)) + shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +After these examples your are probably sick of seeing this picture in color, so +let's turn the colors into a weigthed grayscales (in a way similar to the way +black and white television treated color). + +\startbuffer +loadfigure "gracht.mp" number 1 scaled .5 ; +addto currentpicture also + grayed currentpicture + shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +\stopsection + +% \startsection[title={Outline fonts}] +% +% \index{text+outlines} +% \index{outlines} +% +% Outline fonts don't belong to \METAPOST's repertoire of features. Nevertheless we +% can simulate this in a reasonable way. We will not discuss all details here, +% because most details are covered in the \MAKEMPY\ manual. +% +% The macro responsible for outline fonts is \type {graphictext}. The first +% argument should be a string. This string is processed by \TEX. Additionally you +% can provide transformation directives and color specifications. The next example +% demonstrates this. +% +% \startbuffer +% graphictext "\bf Fun" scaled 4 zscaled (1,1.5) +% withdrawcolor blue +% withfillcolor .5white +% withpen pencircle scaled 5pt +% \stopbuffer +% +% \typebuffer +% +% Once the text is typeset by \TEX, it is converted to \POSTSCRIPT\ and converted +% into \METAPOST\ by the \PSTOEDIT\ program. The resulting graphic is imported, +% analyzed, and processed conforming the specifications of \type {graphictext}. +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% By default the shapes are filled after they are drawn. This has the advantage +% that in characters built out of pieces, disturbing lines fragments are covered. +% The drawback is that you get only half the linewidth. You can reverse the drawing +% order by adding the \type {reversefill} directive. The previous graphic then +% comes out as: +% +% \startbuffer +% graphictext "\bf Fun" scaled 4 zscaled (1,1.5) +% reversefill +% withdrawcolor blue +% withfillcolor .5white +% withpen pencircle scaled 5pt +% \stopbuffer +% +% \typebuffer +% +% The \type {reversefill} directive can be countered by \type {outlinefill}. +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% The next example is taken from the \MAKEMPY\ manual. It demonstrates that you can +% combine \TEX's powerful line breaking with \METAPOST's graphic capabilities. +% +% \startbuffer +% \startuseMPgraphic{quotation} +% picture one ; one := image ( graphictext +% \MPstring{text} +% scaled 1.5 +% withdrawcolor .625blue +% withfillcolor .625white +% withpen pencircle scaled 1pt ; ) ; +% picture two ; two := image ( graphictext +% \MPstring{author} +% scaled 2 +% withdrawcolor .625red +% withfillcolor .625white +% withpen pencircle scaled 2pt ; ) ; +% currentpicture := one ; +% addto currentpicture also two +% shifted lrcorner one +% shifted - 1.125 lrcorner two +% shifted (0, - 1.250 * ypart urcorner two) ; +% setbounds currentpicture to boundingbox currentpicture enlarged 3pt ; +% \stopuseMPgraphic +% \stopbuffer +% +% \typebuffer \getbuffer +% +% In this graphic, we have two text fragments, the first one is a text, the second +% one the name of the author. We combine the quotation and author into this graphic +% using the following definitions: +% +% \startbuffer +% \setMPtext{text} {\vbox{\hsize 8.5cm \input zapf }} +% \setMPtext{author}{\hbox{\sl Hermann Zapf}} +% \stopbuffer +% +% \typebuffer \getbuffer +% +% These definitions assume that the file \type {zapf.tex} is present on the system +% (which is the case when you have installed \CONTEXT). The graphic can now be +% typeset using the following call: +% +% \startbuffer +% \placefigure +% {A text does not need to be an outline in order to be +% typeset in an outline font.} +% {\useMPgraphic{quotation}} +% \stopbuffer +% +% \typebuffer \getbuffer +% +% The quality of the output depends on how the glyphs are constructed. For +% instance, in \TEX, math symbols are sometimes composed of glyph fragments and +% rules. +% +% \startbuffer +% graphictext +% "$$\sqrt{1+x}$$" +% scaled 8 +% withdrawcolor .625red +% withpen pencircle scaled 1.5pt +% \stopbuffer +% +% \typebuffer +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% This is not really a problem because we can also fill the shapes. It is the +% reason why the fill is applied after the draw and in such case the effective line +% width is half the size specified. +% +% \startbuffer +% graphictext +% "$$\left({{\sqrt{1+x}}\over{\sqrt{2+x^2}}}\right)$$" +% scaled 4 +% dashed evenly +% withdrawcolor .625red +% withfillcolor .850white +% withpen pencircle scaled 1.5pt +% \stopbuffer +% +% \typebuffer +% +% In this example we also use a dashed line. Instead of normal colors, we could +% have used shades or transparent colors. +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% Instead of supplying the text directly, you can use the indirect method. This +% permits you to process rather complex data without messing up your \METAPOST\ +% code. +% +% \startbuffer +% \setMPtext {some math}% +% {\usemodule[mathml] +% \xmlprocessdata +% {main} +% {<math xmlns='http://www.w3c.org/mathml' version='2.0'> +% <apply> <log/> +% <logbase> <cn> 2 </cn> </logbase> +% <apply> <plus/> +% <ci> x </ci> +% <cn> 1 </cn> +% </apply> +% </apply> +% </math>} +% {}} +% \stopbuffer +% +% \typebuffer \getbuffer +% +% Here we feed some \MATHML\ into \TEX, which in turn shows up as a \METAPOST\ +% graphic. +% +% \startbuffer +% graphictext +% \MPstring{some math} +% scaled 4 +% withdrawcolor .625red +% withfillcolor .625white +% withpen pencircle scaled 1.5pt +% \stopbuffer +% +% \typebuffer +% +% \startlinecorrection[blank] +% \processMPbuffer +% \stoplinecorrection +% +% \stopsection + +\startsection[title={Outline fonts}] + +\index{text+outlines} +\index{outlines} + +Outline fonts don't belong to \METAPOST's repertoire of features. Nevertheless we +can simulate this in a reasonable way. The current version of \METAFUN\ uses the +outline subsystem of \CONTEXT\ \MKIV, but in earlier days we used an external +process: a \PDF\ file is generated that has the snippet, that gets converted to +\POSTSCRIPT, which in turn is converted to \METAPOST\ with \type {pstoedit} and +from that result we filter the outlines. This method uses \type {graphictext} and +is covered in the \MAKEMPY\ manual. Here we discuss the new method using \type +{outlinetext}. + +\startbuffer +draw outlinetext.b("\bf Funky") + (withcolor .5white) + (withcolor blue withpen pencircle scaled 1/5) + scaled 4 zscaled (1,0.5) ; +\stopbuffer + +\typebuffer + +Once the text is typeset by \TEX, the result (a node list) is parsed and a +\METAPOST\ representation is created. The glyphs are converted to outlines that +are taken from the original font. For the moment this only works for \OPENTYPE\ +fonts. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startbuffer[1] +draw outlinetext ("\bf Funky") + scaled 3 ; +\stopbuffer + +\startbuffer[2] +draw outlinetext.d ("\bf Funky") + (withcolor red withpen pencircle scaled 1/5) + scaled 3 ; +\stopbuffer + +\startbuffer[3] +draw outlinetext.f ("\bf Funky") + (withcolor blue) + scaled 3 ; +\stopbuffer + +\startbuffer[4] +draw outlinetext.b ("\bf Funky") + (withcolor blue) + (withcolor red withpen pencircle scaled 1/5) + scaled 3 ; +\stopbuffer + +\startbuffer[5] +draw outlinetext.r ("\bf Funky") + (withcolor blue) + (withcolor red withpen pencircle scaled 1/5) + scaled 3 ; +\stopbuffer + +\startplacetable[reference=tab:outlinetext,title={The four variants of \type {graphictext}.}] + \bTABLE[offset=1ex] + \dorecurse{5}{\bTR \bTD \processMPbuffer[#1] \eTD \bTD \typebuffer[#1] \eTD \eTR} + \eTABLE +\stopplacetable + +The five variants of this command are shown in \in {table} [tab:outlinetext]: the +suffix determines the number of arguments and rendering. The \type {r} suffix +reverses the order: the fill comes over the draw. There is a \type {p} suffix +that returns just the picture. + +The next example demonstrates that you can combine \TEX's powerful line breaking +algorithm with \METAPOST's graphic capabilities. + +\startbuffer +\startuseMPgraphic{quotation} + picture one ; one := image ( draw outlinetext.b + (\MPstring{text}) + (withcolor .625white) + (withcolor .625blue withpen pencircle scaled 1/5) + scaled 1.5 + ) ; + picture two ; two := image ( draw outlinetext.b + (\MPstring{author}) + (withcolor .625white) + (withcolor .625red withpen pencircle scaled 1/5) + scaled 2 + ) ; + currentpicture := one ; + addto currentpicture also two + shifted lrcorner one + shifted - 1.125 lrcorner two + shifted (0, - 2 * ypart urcorner two) ; + setbounds currentpicture to boundingbox currentpicture enlarged 3pt ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +In this graphic, we have two text fragments, the first one is a text, the second +one the name of the author. We combine the quotation and author into this graphic +using the following definitions: + +\startbuffer +\setMPtext + {text} + {\vbox + {\setupalign[verytolerant,stretch] + \hsize 8.5cm + \input zapf }} +\setMPtext + {author} + {\hbox + {\sl Hermann Zapf}} +\stopbuffer + +\typebuffer \getbuffer + +These definitions assume that the file \type {zapf.tex} is present on the system +(which is the case when you have installed \CONTEXT). The graphic can now be +typeset using the following call: + +\startbuffer +\placefigure + [here] + [fig:zapf] + {A text does not need to be an outline in order to be + typeset in an outline font.} + {\useMPgraphic{quotation}} +\stopbuffer + +\typebuffer + +The result is \in {figure} [fig:zapf]. The quality of the output depends on how +the glyphs are constructed. For instance, in \TEX, math symbols are sometimes +composed of glyph fragments and rules. + +\start + \def||{-} + \getbuffer +\stop + +\startbuffer +draw outlinetext.d + ("\mathematics{\sqrt{1+x}}") + (withcolor .625red withpen pencircle scaled 1/5) + scaled 8 +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This is not really a problem because we can also fill the shapes. It is the +reason why the fill is applied after the draw and in such case the effective line +width is half the size specified. + +\startbuffer +draw outlinetext.b + ("\mathematics{\left({{\sqrt{1+x}}\over{\sqrt{2+x^2}}}\right)}") + (withcolor .850white) + (withcolor .625red + dashed evenly scaled .1 + withpen pencircle scaled 1/5) + scaled 8 +\stopbuffer + +\typebuffer + +In this example (shown in \in {figure} [fig:dashedoutline]) we also use a dashed +line. + +\placefigure + [here] + [fig:dashedoutline] + {A dashed outline text.} + {\processMPbuffer} + +Instead of supplying the text directly, you can use the indirect method. This +permits you to process rather complex data without messing up your \METAPOST\ +code. + +\startbuffer +\usemodule[mathml] + +\setMPtext {some math}% + {\xmlprocessdata + {main} + {<math xmlns='http://www.w3c.org/mathml' version='2.0'> + <apply> <log/> + <logbase> <cn> 2 </cn> </logbase> + <apply> <plus/> + <ci> x </ci> + <cn> 1 </cn> + </apply> + </apply> + </math>} + {}} +\stopbuffer + +\typebuffer \getbuffer + +Here we feed some \MATHML\ into \TEX, which in turn shows up as a \METAPOST\ +graphic (\in {figure} [fig:mathml]). + +\startbuffer +draw outlinetext.b + (\MPstring{some math}) + (withcolor .625white) + (withcolor .625red withpen pencircle scaled 1/5) + scaled 8 +\stopbuffer + +\typebuffer + +\placefigure + [here] + [fig:mathml] + {A \MATHML\ snippet turned into outlines.} + {\processMPbuffer} + +Outlines are fun to look at. Here are a few ways to visualize a glyph: + +\startbuffer[1] +\startcombination[3*1] + {\ruledhbox\bgroup + \showshape[character=(,alternative=text]% + \egroup} {} + {\ruledhbox\bgroup + \showshape[character=a,alternative=text]% + \egroup} {} + {\ruledhbox\bgroup + \showshape[character=x,alternative=text]% + \egroup} {} +\stopcombination +\stopbuffer + +\typebuffer[1] + +You can control the rendering a bit by setting \type {option}. Possible options +are: \type {box}, \type {width}, \type {min}, \type {max} and \type {comment}. +The \type {simple} option disables all. The simple results are shown in +\in{figure} [fig:showshape]. + +\startbuffer[2] +\startcombination[3*1] + {\ruledhbox\bgroup + \showshape[character=(,alternative=text,option=simple]% + \egroup} {} + {\ruledhbox\bgroup + \showshape[character=a,alternative=text,option=simple]% + \egroup} {} + {\ruledhbox\bgroup + \showshape[character=x,alternative=text,option=simple]% + \egroup} {} +\stopcombination +\stopbuffer + +\typebuffer[2] + +\startplacefigure[reference=fig:showshape,title={Showing shapes.}] + \getbuffer[2] +\stopplacefigure + +When you use this feature you need to be aware of the fact that fonts can have +features, for instance ligatures and kerns between characters. In \in {figure} +[fig:outlines:features] we see a few examples with and without features, one with +Pagella (the Zapf quote) and one with Optima Nova (the Tufte quote). + +\startplacefigure[reference=fig:outlines:features,title={Pagela (\OPENTYPE) and Optima Nova (\TYPEONE)}] + \startcombination[1*4] + \bgroup + \def|#1|{-}% + \definedfont[texgyrepagella-regular.otf*none]% + \startMPcode + draw outlinetext.b + ("\framed[align=normal,width=max]{\input{zapf}}") + (withcolor .375white) + (withcolor .625red withpen pencircle scaled 1/10) ; + \stopMPcode + \egroup {pagella / no features} + \bgroup + \def|#1|{-}% + \definedfont[texgyrepagella-regular.otf*default]% + \startMPcode + draw outlinetext.b + ("\framed[align=normal,width=max]{\input{zapf}}") + (withcolor .375white) + (withcolor .625blue withpen pencircle scaled 1/10) ; + \stopMPcode + \egroup {pagella / default features} + \bgroup + \def|#1|{-}% + \definedfont[lt55476.afm*none]% optima nova + \startMPcode + draw outlinetext.b + ("\framed[align=normal,width=max]{\input{tufte}}") + (withcolor .375white) + (withcolor .625green withpen pencircle scaled 1/10) ; + \stopMPcode + \egroup {optima nova / no features} + \bgroup + \def|#1|{-}% + \definedfont[lt55476.afm*default]% optima nova + \startMPcode + draw outlinetext.b + ("\framed[align=normal,width=max]{\input{tufte}}") + (withcolor .375white) + (withcolor .625yellow withpen pencircle scaled 1/10) ; + \stopMPcode + \egroup {optima nova / default features} + \stopcombination +\stopplacefigure + +Given that a shape has a path that is suitable for it, you can use special effects, +like: + +\startbuffer + draw image ( + draw outlinetext.d + ("Abracadabra") + (withpen pencircle scaled 1/10 dashed withdots scaled 1/20) ; + ) xsized TextWidth ; +\stopbuffer + +\typebuffer + +\startlinecorrection + \processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title=Transparency groups] + +The following feature is not that usefull but implemented anyway. The \PDF\ reference says: + +\startitemize + \startitem + A group may be isolated or non-isolated, which shall determine the + initial backdrop against which its stack is composited. + \stopitem + \startitem + A group may be knockout or non-knockout, which shall determine whether + the objects within its stack are composited with one another or only with + the group’s backdrop. + \stopitem +\stopitemize + +and then carries on with a detailed explanation of groups. Here we stick to just +mentioning how one can create a group in a picture. First we define a helper: + +\startbuffer +\startMPdefinitions + def ShowGroup (expr clr) (text grouped) = + draw image ( + drawarrow (10,0) -- (0,0) + withtransparency(1,.5) + withcolor clr ; + ) grouped ; + currentpicture := currentpicture xsized (TextWidth/8) ; + setbounds currentpicture to boundingbox currentpicture enlarged 2mm ; + addbackground withcolor .5white ; + enddef ; +\stopMPdefinitions +\stopbuffer + +\typebuffer \getbuffer + +\startlinecorrection[blank] + \startcombination[5*1] + {\startMPcode ShowGroup(.5red) () \stopMPcode} {\tttf no group} + {\startMPcode ShowGroup(.5green) (asgroup "") \stopMPcode} {\tttf group} + {\startMPcode ShowGroup(.5blue) (asgroup "isolated") \stopMPcode} {\tttf isolated} + {\startMPcode ShowGroup(.5cyan) (asgroup "knockout") \stopMPcode} {\tttf knockout} + {\startMPcode ShowGroup(.5magenta)(asgroup "isolated,knockout") \stopMPcode} {\tttf isolated\crlf knockout} + \stopcombination +\stoplinecorrection + +The syntax is: + +\starttyping +draw somepicture|somepath grouped "[isolated|knockout] ; +\stoptyping + +The group becomes an object and is no longer part of the stream of graphic +operators but a reference. For what it's worth: I never needed this feature. + +\stopsection + +\startsection[title=Decorating] + +Although the \METAPOST\ language is quite powerful the number of data types is +not that large and when it comes to drawing stuff there are only paths and +pictures. A path is a list of points (with controlpoints) and a few properties, +like the pen, linewidth, linecap, color and such. For a long time in \METAFUN\ we +used so called specials to implement extensions (like shading). This was done by +using special colors and associating these with entries in the special section at +the top of the output. + +Nowadays we use the pre- and postscript properties of paths. The advantage is +that we can add whatever we want, as long as the backend supports it and because +the backend is written in \LUA\ there are no real limitations. So, instead of +extending \METAPOST\ we extend the \METAFUN\ macros and backend. + +Most extensions use the prescripts. Think of this: + +\starttyping +draw fullcircle + withprescript "do this" + withprescript "and that" + withprescript "and even more" ; +\stoptyping + +Eventually this becomes a string: + +\starttyping +and even more<newline>and that<newline>do this +\stoptyping + +\typebuffer + +The prescripts get prepended, while the postscripts (that we use for text only) +get appended. When we draw a picture with properties (like color) they get +overwritten but not so (with good reason) for the pre- and postscripts: these +just accumulate. We will now demonstrate how we can manipulate the picture +(a bit). + +\startbuffer +picture MyShape ; MyShape := image ( + fill fullsquare xyscaled (4,1) withcolor .625red ; + fill fullsquare xyscaled (3,1) withcolor .625green ; + fill fullsquare xyscaled (2,1) withcolor .625blue ; + fill fullsquare xyscaled (1,1) withcolor .625yellow ; +) xysized (TextWidth,1cm) ; + +draw MyShape; +\stopbuffer + +\typebuffer + +We just draw the (natural) picture: + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +When we draw the picture with a new color, all its components get recolored: + +\startbuffer +draw MyShape + withcolor .625magenta ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +However, when we add a transparency only the first component gets adapted because +we use prescripts for this extension. (An extension using the postscripts would +affect the last component.) + +\startbuffer +draw MyShape + withcolor .625magenta + withtransparency (1,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +The same logic applied to the \type {image}: prescripts get prepended to the +first copmponent, postscripts to the last. + +\startbuffer +draw image (draw MyShape) + withcolor .625cyan ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +\startbuffer +draw image (draw MyShape) + withcolor .625cyan + withtransparency (1,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +The \type {undecorated} macro ignores the properties. We can't reset the scripts as +this could ruin the effects like shading. + +\startbuffer +draw undecorated (draw MyShape) + withcolor .625white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +The \type {decorated} macro applies the properties to each component. + +\startbuffer +draw decorated (draw MyShape) + withtransparency (1,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +Here we kept the colors as they are but next we redo them: + +\startbuffer +draw decorated (draw MyShape) + withcolor .625magenta + withtransparency (1,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +The \type {redecorated} macro is the most intrusive as it resets the properties. +This also means that you will loose texts, shades etc. + +\startbuffer +draw redecorated (draw MyShape) + withtransparency (1,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +Indeed we get no color (but black) but we can bring back some color: + +\startbuffer +draw redecorated (draw MyShape) + withcolor .625yellow + withtransparency (1,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title=Properties] + +The (plain) \METAPOST\ macro \type {drawoptions} stored its arguments +in a macro that gets expanded when something is drawn (or filled). So, when you say + +\starttyping +drawoptions(withcolor red) ; +draw somepath ; +\stoptyping + +This effectively is: + +\starttyping +draw somepath withcolor red ; +\stoptyping + +A disadvantage is that there is not much control over where it gets applied, +especially when you hide drawing operations in macros. It's the reason why +personally I always prefer explicit options. If you want some abstraction +you can use the properties feature: + +\startbuffer +\startMPcode + property p[] ; + p1 = properties(withcolor "darkred") ; + p2 = properties(withcolor "darkblue") ; + p3 = properties(withcolor "darkgreen") ; + fill fullsquare xysized (TextWidth,12mm) withproperties p1 ; + fill fullsquare xysized (TextWidth, 8mm) withproperties p2 ; + fill fullsquare xysized (TextWidth, 4mm) withproperties p3 ; + fill fullsquare xysized (TextWidth, 2mm) withproperties p1 ; +\stopMPcode +\stopbuffer + +\typebuffer + +We get: + +\startlinecorrection +\getbuffer +\stoplinecorrection + +Here we use an \quote {array} of properties but a single property is also possible: + +\startbuffer +\startMPcode + property p ; + p = properties(withcolor "darkyellow") ; + fill fullsquare xysized (TextWidth,4mm) withproperties p ; +\stopMPcode +\stopbuffer + +\typebuffer + +We get: + +\startlinecorrection +\getbuffer +\stoplinecorrection + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-embedding.tex b/doc/context/sources/general/manuals/metafun/metafun-embedding.tex new file mode 100644 index 000000000..10383fa3a --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-embedding.tex @@ -0,0 +1,1208 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-embedding + +\environment metafun-environment + +\startchapter[reference=sec:embedding,title={Embedded graphics}] + +\startintro + +In addition to the \type {beginfig}||\type {endfig} method, there are other ways +to define and include a \METAPOST\ graphic. Each method has its advantages and +disadvantages. + +In the previous chapter we were still assuming that the graphic was defined in +its own file. In this chapter we will introduce the interface between \CONTEXT\ +and \METAPOST\ and demonstrate how the definitions of the graphics can be +embedded in the document source. + +\stopintro + +\startsection[title={Getting started}] + +\index{running} +\index{processing} + +From now on, we will assume that you have \CONTEXT\ running on your platform. +Since \PDF\ has full graphics support, we also assume that you use \LUATEX\ in +combination with \CONTEXT\ \MKIV, although most will also work with other engines +and \MKII. Since this document is not meant as a \CONTEXT\ tutorial, we will +limit this introduction to the basics needed to run the examples. + +A simple document looks like: + +\starttyping +\starttext + Some text. +\stoptext +\stoptyping + +You can process this document with the \LUA\ based command line interface to +\CONTEXT. If the source code is embedded in the file \type {mytext.tex}, you can +say: + +\starttyping +context mytext +\stoptyping + +We will use color, and in \MKIV\ color is enabled by default. If you don't want +color you can tell \CONTEXT, so + +\starttyping +\setupcolors[state=stop] +\starttext + Some \color[blue]{text} and/or \color[green]{graphics}. +\stoptext +\stoptyping + +comes out in black and white. + +In later chapters we will occasionally see some more \CONTEXT\ commands show up. +If you want to know more about what \CONTEXT\ can do for you, we recommend the +beginners manual and the reference manual, as well as the wiki pages. + +\stopsection + +\startsection[title={External graphics}] + +\index {graphics+external} + +Since \TEX\ has no graphic capabilities built in, a graphic is referred to as an +external figure. A \METAPOST\ graphic often has a number as suffix, so embedding +such a graphic is done by: + +\starttyping +\externalfigure[graphic.123][width=4cm] +\stoptyping + +An alternative method is to separate the definition from the inclusion. An +example of a definition is: + +\starttyping +\useexternalfigure[pentastar][star.803][height=4cm] +\useexternalfigure[octostar] [star.804][pentastar] +\stoptyping + +Here, the second definition inherits the characteristics from the first one. +These graphics can be summoned like: + +\starttyping +\placefigure + {A five||point star drawn by \METAPOST.} + {\externalfigure[pentastar]} +\stoptyping + +Here the stars are defined as stand||alone graphics, in a file called \type +{star.mp}. Such a file can look like: + +\starttyping +def star (expr size, n, pos) = + for a=0 step 360/n until round(360*(1-1/n)) : + draw (origin -- (size/2,0)) + rotatedaround (origin,a) shifted pos ; + endfor ; +enddef ; + +beginfig(803) ; + pickup pencircle scaled 2mm ; star(2cm,5,origin) ; +endfig ; + +beginfig(804) ; + pickup pencircle scaled 1mm ; star(1cm,8,origin) ; + pickup pencircle scaled 2mm ; star(2cm,7,(3cm,0)) ; +endfig ; + +end. +\stoptyping + +This \type {star} macro will produce graphics like: + +\startbuffer +def star (expr size, n, pos) = + for a=0 step 360/n until round(360*(1-1/n)) : + draw (origin -- (size/2,0)) + rotatedaround (origin,a) shifted pos ; + endfor ; +enddef ; + +for i=5 upto 10 : + drawoptions (withpen pencircle scaled 2mm withcolor .625red) ; + star(1cm,i,origin shifted (i*2cm,0)) ; +endfor ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +But, now that we have instant \METAPOST\ available in \LUATEX, there is no need +for external images and we can collect them in libraries, as we will see later +on. + +\stopsection + +\startsection[title={Integrated graphics}] + +\index{graphics+embedded} + +An integrated graphic is defined in the document source or in a style definition +file. The most primitive way of doing this is just inserting the code: + +\starttyping +\startMPcode + fill fullcircle scaled 200pt withcolor .625white ; +\stopMPcode +\stoptyping + +Such a graphic is used once at the spot where it is defined. In this document we +also generate graphics while we finish a page, so there is a good chance that +when we have constructed a graphic which will be called on the next page, the +wrong graphic is placed. + +For this reason there are are more convenient ways of defining and using +graphics, which have the added advantage that you can predefine multiple +graphics, thereby separating the definitions from the usage. + +The first alternative is a {\em usable} graphic. Such a graphic is calculated +anew each time it is used. An example of a usable graphic is: + +\starttyping +\startuseMPgraphic{name} + fill fullcircle scaled 200pt withcolor .625yellow ; +\stopuseMPgraphic +\stoptyping + +When you put this definition in the preamble of your document, you can place this +graphic anywhere in the file, saying: + +\starttyping +\useMPgraphic{name} +\stoptyping + +As said, this graphic is calculated each time it is placed, which can be time +consuming. Apart from the time aspect, this also means that the graphic itself is +incorporated many times. Therefore, for graphics that don't change, \CONTEXT\ +provides {\em reusable} graphics: + +\starttyping +\startreusableMPgraphic{name} + fill fullcircle scaled 200pt withcolor .625yellow; +\stopreusableMPgraphic +\stoptyping + +This definition is accompanied by: + +\starttyping +\reuseMPgraphic{name} +\stoptyping + +Imagine that we use a graphic as a background for a button. We can create a +unique and reusable graphic by saying: + +\starttyping +\def\MyGraphic + {\startreusableMPgraphic{name:\overlaywidth:\overlayheight} + path p ; p := unitsquare + xscaled OverlayWidth yscaled OverlayHeight ; + fill p withcolor .625yellow ; + draw p withcolor .625red ; + \stopreusableMPgraphic + \reuseMPgraphic{name:\overlaywidth:\overlayheight}} +\stoptyping + +Notice the use of \type {OverlayWidth} and \type {OverlayHeight}. These variables +are set for each call to \METAPOST. After this we can say: + +\starttyping +\defineoverlay[my graphic][\MyGraphic] +\button[background=my graphic,frame=off]{Go Home}[firstpage] +\stoptyping + +Say that we have a 30pt by 20pt button, then the identifier will be \type +{name:30pt:20pt}. Different dimensions will lead to other identifiers, so this +sort of makes the graphics unique. + +We can bypass the ugly looking \type {\def} by using a third class of embedded +graphics, the {\em unique} graphics. + +\starttyping +\startuniqueMPgraphic{name} + path p ; p := unitsquare + xscaled OverlayWidth yscaled OverlayHeight ; + fill p withcolor .625yellow ; + draw p withcolor .625red ; +\stopuniqueMPgraphic +\stoptyping + +Now we can say: + +\starttyping +\defineoverlay[my graphic][\uniqueMPgraphic{name}] +\button[background=my graphic,frame=off]{Go Home}[firstpage] +\stoptyping + +A shorter variant is: + +\starttyping +\startuniqueMPgraphic{name} + fill OverlayBox withcolor .625yellow ; + draw OverlayBox withcolor .625red ; +\stopuniqueMPgraphic +\stoptyping + +You may wonder why unique graphics are needed when a single graphic might be used +multiple times by scaling it to fit the situation. Since a unique graphic is +calculated for each distinctive case, we can be sure that the current +circumstances are taken into account. Also, scaling would result in incomparable +graphics. Consider the following definition: + +\startbuffer[a] +\startuseMPgraphic{demo} + draw unitsquare + xscaled 5cm yscaled 1cm + withpen pencircle scaled 2mm + withcolor .625red ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer[a] + +Since we reuse the graphic, the dimensions are sort of fixed, and because the +graphic is calculated once, scaling it will result in incompatible line widths. + +\startbuffer[b] +\hbox \bgroup + \scale[width=5cm,height=1cm]{\useMPgraphic{demo}}\quad + \scale[width=8cm,height=1cm]{\useMPgraphic{demo}}% +\egroup +\stopbuffer + +\startlinecorrection[blank] +\getbuffer[a,b] +\stoplinecorrection + +These graphics were placed with: + +\typebuffer[b] + +Imagine what happens when we add some buttons to an interactive document without +taking care of this side effect. All the frames would look different. Consider +the following example. + +\startbuffer[a] +\startuniqueMPgraphic{right or wrong} + pickup pencircle scaled .075 ; + fill unitsquare withcolor .8white ; + draw unitsquare withcolor .625red ; + currentpicture := currentpicture + xscaled OverlayWidth yscaled OverlayHeight ; +\stopuniqueMPgraphic +\stopbuffer + +\typebuffer[a] + +Let's define this graphic as a background to some buttons. + +\startbuffer[b] +\defineoverlay[button][\uniqueMPgraphic{right or wrong}] +\setupbuttons[background=button,frame=off] +\stopbuffer + +\startbuffer[c] +\hbox + {\button {previous} [previouspage]\quad + \button {next} [nextpage]\quad + \button {index} [index]\quad + \button {table of contents} [content]} +\stopbuffer + +\typebuffer[b,c] + +The buttons will look like: + +\startlinecorrection[blank] +\setupinteraction[state=start,color=,contrastcolor=] +\getbuffer[a,b,c] +\stoplinecorrection + +Compare these with: + +\startbuffer[a] +\startuniqueMPgraphic{wrong or right} + pickup pencircle scaled 3pt ; + path p ; p := unitsquare + xscaled OverlayWidth yscaled OverlayHeight ; + fill p withcolor .8white ; + draw p withcolor .625red ; +\stopuniqueMPgraphic +\stopbuffer + +\startlinecorrection[blank] +\getbuffer[a,b] +\defineoverlay[button][\uniqueMPgraphic{wrong or right}] +\setupinteraction[state=start,color=,contrastcolor=] +\getbuffer[c] +\stoplinecorrection + +Here the graphic was defined as: + +\typebuffer[a] + +The last class of embedded graphics are the {\em runtime} graphics. When a +company logo is defined in a separate file \type {mylogos.mp}, you can run this +file by saying: + +\starttyping +\startMPrun + input mylogos ; +\stopMPrun +\stoptyping + +The source for the logo is stored in a file named \type {mylogos.mp}. + +\startbuffer +beginfig(21) ; + draw fullsquare withcolor .625red ; + draw fullsquare rotated 45 withcolor .625red ; + picture cp ; cp := currentpicture ; + def copy = addto currentpicture also cp enddef ; + copy scaled .9 withcolor .625white ; + copy scaled .7 withcolor .625yellow ; + copy scaled .6 withcolor .625white ; + copy scaled .4 withcolor .625red ; + copy scaled .3 withcolor .625white ; + fill fullcircle scaled .2 withcolor .625yellow ; + currentpicture := currentpicture scaled 50 ; +endfig ; +end . +\stopbuffer + +\typebuffer + +In this example the result is available in the virtual file \type {mprun.21}. +This file can be included in the normal way, using: + +\starttyping +\externalfigure[mprun.21][width=5cm] +\stoptyping + +\startuseMPgraphic{dummy logo} + draw fullsquare withcolor .625red ; + draw fullsquare rotated 45 withcolor .625red ; + picture cp ; cp := currentpicture ; + def copy = addto currentpicture also cp enddef ; + copy scaled .9 withcolor .625white ; + copy scaled .7 withcolor .625yellow ; + copy scaled .6 withcolor .625white ; + copy scaled .4 withcolor .625red ; + copy scaled .3 withcolor .625white ; + fill fullcircle scaled .2 withcolor .625yellow ; + currentpicture := currentpicture scaled 3cm ; +\stopuseMPgraphic + +\placefigure + {The logo is defined in the file \type {mylogos.mp} as + figure~21 and processed by means of the \type {mprun} + method.} + {\useMPgraphic{dummy logo}} + +Optionally you can specify a name and an instance. This has the advantage that +the graphics don't interfere with the regular inline graphics. Here the instance +used is \type {extrafun} and the name where the run is stored is \type {mydemo}. + +\startbuffer +\startMPrun{extrafun::mydemo} + input mfun-mrun-demo.mp ; +\stopMPrun + +\placefigure + {An external file can have multiple graphics. Here we show a few + images that we used to use on the \PRAGMA\ \CONTEXT\ website.} + {\startcombination[2*2] + {\externalfigure[mprun:extrafun::mydemo.1][height=6cm]} {downloads} + {\externalfigure[mprun:extrafun::mydemo.2][height=6cm]} {links} + {\externalfigure[mprun:extrafun::mydemo.3][height=6cm]} {mirrors} + {\externalfigure[mprun:extrafun::mydemo.4][height=6cm]} {team} + \stopcombination} +\stopbuffer + +\typebuffer + +Keep in mind that the whole file will be processed (using the built in library) +in order to get one graphic. Normally this is no big deal. + +\getbuffer + +\stopsection + +\startsection[title={Using \METAFUN\ but not \CONTEXT}] + +\index{graphics+standalone} + +If you don't want to use \CONTEXT\ but still want to use \METAFUN, a rather +convenient method is the following. Create a file that + +\starttyping +\startMPpage + % Your mp code goes here. You can use the textext + % macro as discussed later to deal with typeset text. +\stopMPpage +\stoptyping + +When you process that file with the \type {context} command you will get a \PDF\ +file that you can include in any application that can embed a \PDF\ image. In +this case your exposure to \CONTEXT\ is minimal. + +\stopsection + +\startsection[title={Graphic buffers}] + +\index{graphics+buffers} +\index{buffers} + +In addition to the macros defined in the previous section, you can use \CONTEXT's +buffers to handle graphics. This can be handy when making documentation, so it +makes sense to spend a few words on them. + +A buffer is a container for content that is to be (re|)|used later on. The main +reason for their existence is that they were needed for typesetting manuals and +articles on \TEX. By putting the code snippets in buffers, we don't have to key +in the code twice, since we can either show the code of buffers verbatim, or +process the code as part of the text flow. This means that the risk of mismatch +between the code shown and the typeset text is minimized. + +\startbuffer[a] +\startbuffer +You are reading the \METAFUN\ manual. +\stopbuffer +\stopbuffer + +\typebuffer[a] + +This buffer can be typeset verbatim using \type {\typebuffer} and processed using +\type {\getbuffer}, as we will do now: + +\blank \getbuffer[a] \blank + +An other advantage of using buffers, is that they help you keeping the document +source clean. In many places in this manual we put table or figure definitions in +a buffer and pass the buffer to another command, like: + +\starttyping +\placefigure{A very big table}{\getbuffer} +\stoptyping + +Sometimes it makes sense to collect buffers in separate files. In that case we +give them names. + +\startbuffer +\startbuffer[mfun] +You are reading the \METAFUN\ manual. +\stopbuffer +\stopbuffer + +This time we should say \type {\typebuffer[mfun]} to typeset the code verbatim. +Instead of \TEX\ code, we can put \METAPOST\ definitions in buffers. + +\startbuffer +\startbuffer[graphic] +draw fullcircle scaled 2cm ; +\stopbuffer +\stopbuffer + +Buffers can be used to stepwise build graphics. By putting code in multiple +buffers, you can selectively process this code. + +\startbuffer +\startbuffer[red] +drawoptions(withcolor .625red) ; +\stopbuffer + +\startbuffer[yellow] +drawoptions(withcolor .625yellow) ; +\stopbuffer +\stopbuffer + +\typebuffer + +We can now include the same graphic in two colors by simply using different +buffers. This time we use the special command \type {\processMPbuffer}, since +\type {\getbuffer} will typeset the code fragment, which is not what we want. + +\startbuffer +\startlinecorrection[blank] +\processMPbuffer[red,graphic] +\stoplinecorrection +\stopbuffer + +\typebuffer + +The line correction macros take care of proper spacing around the graphic. The +\type {[blank]} directive tells \CONTEXT\ to add more space before and after the +graphic. + +\startbuffer +\startlinecorrection[blank] +\processMPbuffer[yellow,graphic] +\stoplinecorrection +\stopbuffer + +\typebuffer + +Which mechanism you use, (multiple) buffers or (re|)|usable graphics, depends on +your preferences. Buffers are slower but don't take memory, while (re|)|usable +graphics are stored in memory which means that they are accessed faster. + +\stopsection + +\startsection[title={Communicating color}] + +\index{color} + +Now that color has moved to the desktop, even simple documents have become more +colorful, so we need a way to consistently apply color to text as well as +graphics. In \CONTEXT, colors are called by name. + +The next definitions demonstrate that we can define a color using different color +models, \RGB\ or \CMYK. Depending on the configuration, \CONTEXT\ will convert +one color system to the other, \RGB\ to \CMYK, or vice versa. The full repertoire +of color components that can be set is as follows. + +\starttyping +\definecolor[color one] [r=.1, g=.2, b=.3] +\definecolor[color two] [c=.4, m=.5, y=.6, k=.7] +\definecolor[color three][s=.8] +\stoptyping + +The numbers are limited to the range $0\dots1$ and represent percentages. Black +is represented by: + +\starttyping +\definecolor[black 1] [r=0, g=0, b=0] +\definecolor[black 2] [c=0, m=0, y=0, k=1] +\definecolor[black 3] [s=0] +\stoptyping + +Predefined colors are passed to \METAPOST\ graphics via the \type {\MPcolor}. +First we define some colors. + +\starttyping +\definecolor[darkyellow][y=.625] % a CMYK color +\definecolor[darkred] [r=.625] % a RGB color +\definecolor[darkgray] [s=.625] % a gray scale +\stoptyping + +These are the colors we used in this document. The next example uses two of them. + +\startbuffer +\startuseMPgraphic{color demo} + pickup pencircle scaled 1mm ; + path p ; p := fullcircle xscaled 10cm yscaled 1cm ; + fill p withcolor \MPcolor{darkgray} ; + draw p withcolor \MPcolor{darkred} ; +\stopuseMPgraphic + +\useMPgraphic{color demo} +\stopbuffer + +\typebuffer + +The previous example uses a pure \RGB\ red shade, combined with a gray fill. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +Originally \METAPOST\ only supported only the \RGB\ and gray color spaces. In \METAFUN\ +we also supported \CMYK\ and spot colors, using an extension mechanism that hooked into +the backend. At some point \METAPOST\ got native support for \CMYK. When you use mixed +color models you need to be aware of the fact that their related variables have different +types: + +\starttabulate[||T|T|] +\NC gray \NC numeric \NC s \NC \NR +\NC rgb \NC color \NC (r,g,b) \NC \NR +\NC cmyk \NC cmykcolor \NC (c,m,y,k) \NC \NR +\stoptabulate + +Because in \METAFUN\ (\type {mpiv}) we hook deeply into the \CONTEXT\ color +mechanisms we can use symbolic names instead. and these are just strings. + +There is a fundamental difference between a yellow as defined in \CONTEXT\ using +\CMYK\ and a \RGB\ yellow. + +\startbuffer +\definecolor[cmyyellow] [y=1] +\definecolor[rgbyellow] [r=1,g=1] + +\definecolor[cmydarkyellow][y=.625] +\definecolor[rgbdarkyellow][r=.625,g=.625] +\stopbuffer + +\typebuffer \getbuffer + +\in {Figure} [fig:many yellows:pass] demonstrates what happens when we multiply +colors by a factor. Since we are not dealing with real \CMYK\ colors, +multiplication gives different results for \CMYK\ colors passed as \type +{\MPcolor}. \in {Figure} [fig:many yellows:fetch] we show the same colors but +this time we use a different method, one that avoids the \TEX\ macro. This method +can be used in \MKIV. We will use both methods in examples. + +\def\TestColor#1% + {\startuseMPgraphic{yellow} + fill unitsquare xscaled (.30*\the\hsize) yscaled 1cm withcolor #1 ; + \stopuseMPgraphic + \useMPgraphic{yellow}} + +\startbuffer +\setuptype[style=\ttx]% +\startcombination[3*3] + {\TestColor{(0,0,1,0)}} {\type{(0,0,1,0)}} + {\TestColor{(1,1,0)}} {\type{(1,1,0)}} + {\TestColor{(.5,.5,0)}} {\type{(.5,.5,0)}} + {\TestColor{\MPcolor{rgbyellow}}} {\type{\MPcolor{rgbyellow}}} + {\TestColor{\MPcolor{rgbdarkyellow}}} {\type{\MPcolor{rgbdarkyellow}}} + {\TestColor{.5\MPcolor{rgbyellow}}} {\type{.5\MPcolor{rgbyellow}}} + {\TestColor{\MPcolor{cmyyellow}}} {\type{\MPcolor{cmyyellow}}} + {\TestColor{\MPcolor{cmydarkyellow}}} {\type{\MPcolor{cmydarkyellow}}} + {\TestColor{.5\MPcolor{cmyyellow}}} {\type{.5\MPcolor{cmyyellow}}} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:many yellows:pass] + {All kinds of yellow (passing valued from \TEX).} + {\getbuffer} + +\startbuffer +\setuptype[style=\ttx]% +\startcombination[3*3] + {\TestColor{(0,0,1,0)}} {\type{(0,0,1,0)}} + {\TestColor{(1,1,0)}} {\type{(1,1,0)}} + {\TestColor{(.5,.5,0)}} {\type{(.5,.5,0)}} + {\TestColor{"rgbyellow"}} {\type{"rgbyellow"}} + {\TestColor{"rgbdarkyellow"}} {\type{"rgbdarkyellow"}} + {\TestColor{.5namedcolor("rgbyellow")}} {\type{.5namedcolor("rgbyellow")}} + {\TestColor{"cmyyellow"}} {\type{"cmyyellow"}} + {\TestColor{"cmydarkyellow"}} {\type{"cmydarkyellow"}} + {\TestColor{.5namedcolor("cmyyellow")}} {\type{.5namedcolor("cmyyellow")}} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:many yellows:fetch] + {All kinds of yellow (fetching values from \TEX).} + {\getbuffer} + +So, \type {.625red} is the same as \type {[r=.5]}, but \type {.625yellow} is not +the same as \type {[y=.5]}, but matches \type {[r=.5,g=.5]}. \in {Figure} +[fig:some reds] shows the pure and half reds. + +\def\TestColor#1% + {\startMPcode + fill unitsquare xscaled (.30*\the\hsize) yscaled 1cm withcolor #1 ; + \stopMPcode} + +\startbuffer +\setuptype[style=\ttx]\setupcolors[mpcmyk=no] +\startcombination[3*2] + {\TestColor{red}} {\type{red}} + {\TestColor{(1,0,0)}} {\type{(1,0,0)}} + {\TestColor{(.625,0,0)}} {\type{(.625,0,0)}} + {\TestColor{"red"}} {\type{"red")}} + {\TestColor{"darkred"}} {\type{"darkred")}} + {\TestColor{.625namedcolor("red")}} {\type{.625namedcolor("red")}} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:some reds] + {Some kinds of red.} + {\getbuffer} + +In order to prevent problems, we advise you to stick to \RGB\ color +when you create documents for screen and \CMYK\ when producing for print. + +In the \METAFUN\ macro collection there is a macro \type {cmyk} that takes four +arguments, representing the cyan, magenta, yellow, and black component. Nowadays +you don't need it as we have native \CMYK. + +\startbuffer +fill unitsquare xyscaled (10cm, 5mm) withcolor cmyk(1,0,.3,.3) ; +fill unitsquare xyscaled (10cm,-5mm) withcolor (1,.3,0,.3) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +If you take a close look at the numbers, you will notice that the cyan component +results in a 100\% ink contribution. You will also notice that 30\% black ink is +added. This means that we cannot safely convert this color to \RGB\ ($r=1-c-k<0$) +without losing information. Nevertheless the previous blue bar is presented all +right. This is due to the fact that in \METAFUN\ the \CMYK\ colors are handled as +they should, even when \METAPOST\ does not support this color model. + +If you use this feature independent of \CONTEXT, you need to enable it by setting +\type {cmykcolors} to \type {true}. You have to convert the resulting graphic to +\PDF\ by using for instance the \type {mptopdf} suite. + +In \CONTEXT\ you can influence this conversion by changing parameters related to +color handling: + +\starttyping +\setupcolors[cmyk=yes,rgb=no] +\stoptyping + +Unless you know what you are doing, you don't have to change the default settings +(both \type {yes}). In the \CONTEXT\ reference manual you can also read how color +reduction can be handled. + +Special care should be paid to gray scales. Combining equal quantities of the +three color inks will not lead to a gray scale, but to a muddy brown shade. + +\startbuffer +fill fullsquare xyscaled (10cm, 2cm) withcolor .5white ; +fill fullsquare xyscaled ( 6cm,1.5cm) withcolor cmyk(.5,.5,.5,0) ; +fill fullsquare xyscaled ( 2cm, 1cm) withcolor cmyk(0,0,0,.5) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +In \in {figure} [fig:cmyk 1] \in {and} [fig:cmyk 2] you can see some more colors +defined in the \CMYK\ color space. When you display the screen version of this +document, you will notice that the way colors are displayed can differ per +viewer. This is typical for \CMYK\ colors and has to do with the fact that some +assumptions are made with respect to the (print) medium. + +\startbuffer[mp] + fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ; +\stopbuffer + +\startbuffer[cmyk] +\startcombination[4*1] + {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3} + {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15} + {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8} + {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:cmyk 1] + {\CMYK\ support enabled.} + {\getbuffer[cmyk]} + +\placefigure + [here][fig:cmyk 2] + {\CMYK\ support disabled, no support in \METAPOST.} + {\setupcolors[cmyk=no]\getbuffer[cmyk]\setupcolors[cmyk=yes]} + +\stopsection + +% \startsection[title={Common definitions}] +% +% \index{inclusions} +% \index{common definitions} +% +% When using many graphics, there is a chance that they share common definitions. +% Such shared components can be defined by: +% +% \starttyping +% \startMPinclusions +% color mycolor ; mycolor := .625red ; +% \stopMPinclusions +% \stoptyping +% +% {\em The following is only true for \CONTEXT\ \MKII ! Users of \MKIV\ can skip +% this section.} +% +% All \METAPOST\ graphics defined in the document end up in the files \type +% {mpgraph.mp} and \type {mprun.mp}. When processed, they produce (sometimes many) +% graphic files. When you use \CONTEXT\ \MKII\ and \TEXEXEC\ to process documents, +% these two files are processed automatically after a run so that in a next run, +% the right graphics are available. +% +% When you are using the \type {web2c} distribution, \CONTEXT\ can call \METAPOST\ +% at runtime and thereby use the right graphics instantaneously. In order to use +% this feature, you have to enable \type {\write18} in the file \type {texmf.cnf}. +% Also, in the file \type {cont-sys.tex}, that holds local preferences, or in the +% document source, you should say: +% +% \starttyping +% \runMPgraphicstrue +% \stoptyping +% +% This enables runtime generation of graphics using the low level \TEX\ command +% \type {\write18}. First make sure that your local brand of \TEX\ supports this +% feature. A simple test is making a \TEX\ file with the following line: +% +% \starttyping +% \immediate\write18{echo It works} +% \stoptyping +% +% If this fails, you should consult the manual that comes with your system, locate +% an expert or ask around on the \CONTEXT\ mailing list. Of course you can also +% decide to let \TEXEXEC\ take care of processing the graphics afterwards. This has +% the advantage of being faster but has the disadvantage that you need additional +% \TEX\ runs. +% +% If you generate the graphics at run time, you should consider to turn on graphic +% slot recycling, which means that you often end up with fewer intermediate files: +% +% \starttyping +% \recycleMPslotstrue +% \stoptyping +% +% There are a few more low level switches and features, but these go beyond the +% purpose of this manual. Some of these features, like the option to add tokens to +% \type {\everyMPgraphic} are for experts only, and fooling around with them can +% interfere with existing features. +% +% \stopsection + +\startsection[title={One page graphics}] + +An advantage of using \CONTEXT\ to make your \METAPOST\ graphics is you don't +have to bother about specials, font inclusion and all those nasty things that can +spoil a good day. An example of such a graphic is the file \type {mfun-800} that +resides on the computer of the author. + +\typefile{mfun-800} + +Given that \CONTEXT\ is present on your system, you can process this file with: + +\starttyping +context mfun-800 +\stoptyping + +You can define many graphics in one file. Later you can include individual pages +from the resulting \PDF\ file in your document: + +\startbuffer +\placefigure + {A silly figure, demonstrating that stand||alone||graphics + can be made.} + {\typesetfile[mfun-800.tex][page=1]} +\stopbuffer + +\typebuffer + +In this case the \type {page=1} specification is not really needed. You can scale +and manipulate the figure in any way supported by the macro package that you use. + +\getbuffer + +\stopsection + +\startsection[title={Managing resources}] + +A graphic consists of curves, either or not filled with a given color. A graphic +can also include text, which means that fonts are used. Finally a graphic can +have special effects, like a shaded fill. Colors, fonts and special effects go +under the name resources, since they may demand special care or support from the +viewing or printing device. + +% When fonts are used, a \METAPOST\ file is not self contained. This means that the +% postprocessing program has to deal with the fonts. In \CONTEXT, the special +% driver |<|and \PDFTEX\ support is considered as such|>| takes care of this. + +Special effects, like shading, are supported by dedicated \METAPOST\ modules. +These are included in the \CONTEXT\ distribution and will be discussed later in +\in {chapter} [sec:effects]. + +Since \METAPOST\ supports color, an embedded graphic can be rather colorful. +However, when color support is disabled or set up to convert colors to gray +scales, \CONTEXT\ will convert the colors in the graphics to gray scales. + +\startbuffer[circle] + colorcircle(4cm,red,green,blue) ; +\stopbuffer + +\startbuffer +\startcombination[3*1] + {\setupcolors[state=start]\processMPbuffer[circle]} {full color} + {\setupcolors[state=stop]\processMPbuffer[circle]} {weighted gray} + {\setupcolors[state=stop,factor=no]\processMPbuffer[circle]} {linear gray} +\stopcombination +\stopbuffer + +You may wonder what the advantage is of weighted gray conversion. \in {Figure} +[fig:color circles] shows the difference between natural colors, weighted gray +scales and straightforward, non||weighted, gray scales. + +\placefigure + [here][fig:color circles] + {The advantage of weighted gray over linear gray.} + {\getbuffer\setupcolors[state=start,factor=yes]} % just to be sure + +When we convert color to gray, we use the following formula. This kind of +conversion also takes place in black and white televisions. + +\placeformula [-] + \startformula + G = .30r + .59g + .11b + \stopformula + +\in {Section} [sec:conversion] introduces the \type {grayed} operation that you +can use to convert a colored picture into a gray one. This macro uses the same +conversion method as mentioned here. + +\stopsection + +\startsection[title={Instances}] + +There are a few instances predefined and if you want to isolate your own +graphics from whatever \CONTEXT\ itself cooks up, you can define more as the +extra overhead can be neglected. + +\starttabulate[|T|T|T|T|T|] +\BC name \BC format \BC extensions \BC initializations \BC method \NC \NR +\NC metafun \NC metafun \NC yes \NC yes \NC \NC \NR +\NC extrafun \NC metafun \NC yes \NC yes \NC \NC \NR +\NC lessfun \NC metafun \NC \NC \NC \NC \NR +\NC doublefun \NC metafun \NC yes \NC yes \NC double \NC \NR +\NC binaryfun \NC metafun \NC yes \NC yes \NC binary \NC \NR +\NC decimalfun \NC metafun \NC yes \NC yes \NC decimal \NC \NR +\stoptabulate + +According to this the \type {doublefun} instance is defined as: + +\starttyping +\defineMPinstance + [doublefun] + [format=metafun, + extensions=yes, + initializations=yes, + method=double] +\stoptyping + +The \type {extensions} key relates to: + +\starttyping +\startMPextensions + % some code +\stopMPextensions +\stoptyping + +that are used to pass (common) extensions to the instance. The \type +{initializations} key relates to: + +\starttyping +\startMPinitializations + % some code +\stopMPinitializations +\stoptyping + +that are used to communicate \TEX\ properties to the instance (they are +expanded each graphic). Instance bound definitions can be set with: + +\starttyping +\startMPdefinitions{doublefun} + % some code +\stopMPdefinitions +\stoptyping + +We do have more instances, for instance for the chemical subsystem. If you load +the \type {graph} module you get a double precision \type {graph} instance. We might +use more private ones in the future. + +When you make graphic pages, you can do this: + +\starttyping +\startMPpage[instance=doublefun] + % some code +\stopMPpage +\stoptyping + +When you use the other commands you can optionally specify an instance: + +\startbuffer[metafun] +\startMPcode{metafun} + draw textext(decimal pi) scaled 2 withcolor .625red ; + draw boundingbox currentpicture enlarged 2pt ; +\stopMPcode +\stopbuffer + +\startbuffer[extrafun] +\startMPcode{extrafun} + draw textext(decimal pi) scaled 2 withcolor .625green ; + draw boundingbox currentpicture enlarged 2pt ; +\stopMPcode +\stopbuffer + +\startbuffer[doublefun] +\startMPcode{doublefun} + draw textext(decimal pi) scaled 2 withcolor .625blue ; + draw boundingbox currentpicture enlarged 2pt ; +\stopMPcode +\stopbuffer + +\startbuffer[binaryfun] +\startMPcode{binaryfun} + draw textext(decimal pi) scaled 2 withcolor .625yellow ; + draw boundingbox currentpicture enlarged 2pt ; +\stopMPcode +\stopbuffer + +\startbuffer[decimalfun] +\startMPcode{decimalfun} + draw textext(decimal pi) scaled 2 withcolor .375white ; + draw boundingbox currentpicture enlarged 2pt ; +\stopMPcode +\stopbuffer + +\typebuffer[metafun,extrafun,doublefun,binaryfun,decimalfun] + +The result is shown in \in {figure} [fig:instances] and as expected there +is a different value for $\pi$ reported. + +\startplacefigure[reference=fig:instances,title={Instances can use different number systems.}] + \startcombination[1*5] + {\getbuffer[metafun]} {metafun} + {\getbuffer[extrafun]} {extrafun} + {\getbuffer[doublefun]} {doublefun} + {\getbuffer[binaryfun]} {binaryfun} + {\getbuffer[decimalfun]} {decimalfun} + \stopcombination +\stopplacefigure + +You need to be aware of the fact that the results of a (for instance) double +instance can differ from a scaled (the default) one. As long as graphics can be +processed in both models (which is the case as long as the dimensions stay below +4096 base points) the outcome is probably not that different. However, we've seen +that the accuracy of for instance $\pi$ (just a variable) differs. I like to use +random values and the random generators are definitely different: each of the +number libraries has its own implementation. Let's look at that. We define two +random graphic generators: + +\startbuffer +\startuseMPgraphic{normaldeviate} + randomseed := 100 ; + draw fullsquare + withpen pencircle scaled 1/200 + withcolor .5white ; + for i=1 upto 500 : + draw (normaldeviate,normaldeviate) + scaled 1/3 + withpen pencircle scaled 1/30 + withtransparency (1,.5) ; + endfor ; + setbounds currentpicture to + boundingbox fullcircle + enlarged 1/2 ; + currentpicture := + currentpicture + xsized (2TextWidth/5) ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +And: + +\startbuffer +\startuseMPgraphic{uniformdeviate} + randomseed := 100 ; + draw fullsquare + withpen pencircle scaled 1/200 + withcolor .5white ; + for i=1 upto 500 : + draw (-1/2 + uniformdeviate 1,-1/2 + uniformdeviate 1) + withpen pencircle scaled 1/30 + withtransparency (1,.5) ; + endfor ; + setbounds currentpicture to + boundingbox fullcircle + enlarged 1/2 ; + currentpicture := + currentpicture + xsized (2TextWidth/5) ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +We show the results for a normaldeviate in \in {figure} [fig:random:1] \in {upto} +[fig:random:4] you see the randomizers per number system. In \in {figure} +[fig:random:compared] we demonstrate that the scaled version has its own variant. + +\unexpanded\def\TestRandomFun#1#2#3% + {\startMPcode{#1} + draw image(\includeMPgraphic{#2}) + withcolor #3 ; + \stopMPcode} + +\startplacefigure[reference=fig:random:1,title={The scaled randomizers.}] + \pushrandomseed + \startcombination + {\TestRandomFun{metafun} {normaldeviate} {darkred}} {normaldeviate} + {\TestRandomFun{metafun} {uniformdeviate}{darkred}} {uniformdeviate} + \stopcombination + \poprandomseed +\stopplacefigure + +\startplacefigure[reference=fig:random:2,title={The double randomizers.}] + \pushrandomseed + \startcombination + {\TestRandomFun{doublefun} {normaldeviate} {darkgreen}} {normaldeviate} + {\TestRandomFun{doublefun} {uniformdeviate}{darkgreen}} {uniformdeviate} + \stopcombination + \poprandomseed +\stopplacefigure + +\startplacefigure[reference=fig:random:3,title={The decimal randomizers.}] + \pushrandomseed + \startcombination + {\TestRandomFun{decimalfun}{normaldeviate} {darkblue}} {normaldeviate} + {\TestRandomFun{decimalfun}{uniformdeviate}{darkblue}} {uniformdeviate} + \stopcombination + \poprandomseed +\stopplacefigure + +\startplacefigure[reference=fig:random:4,title={The binary randomizers.}] + \pushrandomseed + \startcombination + {\TestRandomFun{binaryfun} {normaldeviate} {darkyellow}} {normaldeviate} + {\TestRandomFun{binaryfun} {uniformdeviate}{darkyellow}} {uniformdeviate} + \stopcombination + \poprandomseed +\stopplacefigure + +\startplacefigure[reference=fig:random:compared,title={Normaldeviate and uniformdeviate overlayed.}] + \pushrandomseed + \startcombination[2*1] + \bgroup + \startoverlay + {\TestRandomFun{metafun} {normaldeviate} {darkred}} + {\TestRandomFun{doublefun} {normaldeviate} {darkgreen}} + {\TestRandomFun{decimalfun}{normaldeviate} {darkblue}} + {\TestRandomFun{binaryfun} {normaldeviate} {darkyellow}} + \stopoverlay + \egroup {normaldeviate} + \bgroup + \startoverlay + {\TestRandomFun{metafun} {uniformdeviate}{darkred}} + {\TestRandomFun{doublefun} {uniformdeviate}{darkgreen}} + {\TestRandomFun{decimalfun}{uniformdeviate}{darkblue}} + {\TestRandomFun{binaryfun} {uniformdeviate}{darkyellow}} + \stopoverlay + \egroup {uniformdeviate} + \stopcombination + \poprandomseed +\stopplacefigure + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-environment-layout.tex b/doc/context/sources/general/manuals/metafun/metafun-environment-layout.tex new file mode 100644 index 000000000..409839cba --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-environment-layout.tex @@ -0,0 +1,151 @@ +\startenvironment metafun-environment-layout + +\setupsystem + [random=big] + +\setupfootertexts + [section][] % [Preliminary Version \currentdate][] + [][section] % [][Preliminary Version \currentdate] + +\useMPlibrary + [clp,txt] + +\definepapersize + [mine] + [width=21cm, + height=28cm] + +\setuppapersize + [mine] + [A4] + +\setuplayout + [topspace=1cm, + backspace=3cm, + cutspace=3cm, + leftmargin=.75cm, + leftmargindistance=.5cm, + rightmargin=1.25cm, + rightmargindistance=1cm, + header=1cm, + headerdistance=1cm, + footer=1cm, + footerdistance=1cm, + width=middle, + height=middle, + % marking=on, + location=middle] + +\startmode[book] + + % \definepapersize + % [mine] + % [width=21cm, + % height=24cm] + % + % \setuppapersize + % [mine] + % [oversized] + % + % \setuplayout + % [backspace=2.5cm, + % cutspace=3.5cm] + + \setuplayout + [marking=on, + scale=\luaexpr{24/28}] + +\stopmode + +\startmode[print] + + \setuppapersize + [mine] + [mine] + +\stopmode + +\setupcolumns + [distance=1cm] + +\setuppagenumbering + [alternative=doublesided] + +\definetypeface [metafunbodyfont] [rm] [serif] [pagella] [default] +\definetypeface [metafunbodyfont] [ss] [sans] [modern] [default] +\definetypeface [metafunbodyfont] [tt] [mono] [modern] [default] +\definetypeface [metafunbodyfont] [mm] [math] [palatino] [default] + +\setupbodyfont [metafunbodyfont,10pt] % 11 pt and 12pt -> errors due to intersection mess + +\definefont[RotFont][RegularBold*default] + +% \setupindenting +% [medium,yes] + +\setupwhitespace + [medium] + +\setuptyping + [margin=standard, + blank=halfline] + +\definecolor [darkred] [r=.625] +\definecolor [darkyellow] [r=.625,g=.625] % not: [y=.625] +\definecolor [darkgray] [s=.625] +\definecolor [lightgray] [s=.875] + +\definecolor [metafun] [darkred] + +\startMPinclusions + color darkred ; darkred := \MPcolor{darkred} ; + color darkyellow ; darkyellow := \MPcolor{darkyellow} ; + color darkgray ; darkgray := \MPcolor{darkgray} ; + color lightgray ; lightgray := \MPcolor{lightgray} ; +\stopMPinclusions + +\setupinteraction % otherwise funny page dimensions due to + [state=start, % grouping half way the file in demo text + style=, + color=, + contrastcolor=] + +% \enabledirectives[refences.linkmethod=page] + +% \setupstructure % needs \startchapter +% [state=start] + +\placebookmarks + [chapter,title,section] + [all] + [force=yes] + +\setuptolerance + [verytolerant] + +\definestartstop + [intro] + [style=slanted, + after=\blank] + +\setupquote + [before=\blank\startnarrower, + after=\stopnarrower\blank] + +\setuplist + [chapter] + [after={\blank[line]}] + +\setupcombinedlist + [content] + [aligntitle=yes, + alternative=c, + interaction=all] + +\setuptabulate + [rulecolor=darkyellow, + rulethickness=1pt] + +\setuplist[chapter][style=bold] + +\stopenvironment diff --git a/doc/context/sources/general/manuals/metafun/metafun-environment-samples.tex b/doc/context/sources/general/manuals/metafun/metafun-environment-samples.tex new file mode 100644 index 000000000..5991a61d5 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-environment-samples.tex @@ -0,0 +1,321 @@ +\startenvironment metafun-environment-sample + +\startuseMPgraphic{sample setup} + numeric Scale ; Scale := 2cm ; + numeric Size ; Size := 2.5mm/Scale ; + numeric Pen ; Pen := .25mm/Scale ; + path Path ; + pickup pencircle scaled (4Pen) ; + def InRed = withcolor .625red enddef ; + def InYellow = withcolor .625yellow enddef ; + def InGray = withpen pencircle scaled Pen withcolor .625white enddef ; + def InBetween= withpen pencircle scaled (4Pen) withcolor .800white enddef ; + def InBlack = withpen pencircle scaled Pen enddef ; + def InWhite = withpen pencircle scaled Pen withcolor white enddef ; + def DrawArrow text t = + draw t ; Path := boundingbox currentpicture ; + drawarrow t ; setbounds currentpicture to Path ; + enddef ; + def ColorCircle = + fill llcircle withcolor .625red ; + fill lrcircle withcolor .625green ; + fill urcircle withcolor .625blue ; + fill ulcircle withcolor .625yellow ; + enddef ; + evenly := dashpattern(on (3mm/Scale) off (3mm/Scale)) ; + withdots := dashpattern(off (2.5mm/Scale) on 0 off (2.5mm/Scale)) ; + ahlength := 4mm/Scale ; ahangle := 30 ; + draw (origin shifted (0,Size)--origin shifted (0,-Size)) ; + draw (origin shifted (Size,0)--origin shifted (-Size,0)) ; + picture Origin ; Origin := currentpicture ; + setbounds Origin to origin--cycle ; + currentpicture := nullpicture ; +\stopuseMPgraphic + +\startuseMPgraphic{sample finish} + draw boundingbox currentpicture InBlack ; + draw Origin InGray ; + currentpicture := currentpicture scaled Scale ; +\stopuseMPgraphic + +% fm = metafun macro +% fv = metafun variable +% mc = metapost concept +% mm = metapost macro +% mp = metapost primitive +% mv = metapost variable + +\starttexdefinition unexpanded DoDoSampleHead#1#2#3 + \setbox\scratchbox\vbox { + \tabskip\zeropoint + \tt\tfx + \halign { + \strut\hss##\unskip\unskip + \cr#3\cr#1\cr + } + } + \ht\scratchbox\ht\strutbox + \dp\scratchbox\dp\strutbox + \noligature{#2}\black + \hfill + \box\scratchbox + \ignorespaces +\stoptexdefinition + +\starttexdefinition unexpanded DoSampleHead #1#2#3 + \processaction + [#1] + [fm=>\DoDoSampleHead{metafun macro}{#2}{#3}, + fv=>\DoDoSampleHead{metafun variable}{#2}{#3}, + mc=>\DoDoSampleHead{metapost concept}{#2}{#3}, + mm=>\DoDoSampleHead{metapost macro}{#2}{#3}, + mp=>\DoDoSampleHead{metapost primitive}{#2}{#3}, + mv=>\DoDoSampleHead{metapost variable}{#2}{#3}] +\stoptexdefinition + +\starttexdefinition unexpanded SampleHead #1#2#3 + \expanded{\extrosubject{\DoSampleHead{#1}{#2}{\detokenize{#3}}}} +\stoptexdefinition + +\starttexdefinition unexpanded StartSample + \doquintuplegroupempty\doStartSample +\stoptexdefinition + +\starttexdefinition unexpanded StopSample + % dummy +\stoptexdefinition + +\starttexdefinition unexpanded doStartSample #1#2#3#4#5#6 StopSample + \bgroup + \SampleHead{#1}{#2}{#3} + \startuseMPgraphic{dummy} + \includeMPgraphic{sample setup} + #6 + \includeMPgraphic{sample finish} + \stopuseMPgraphic + \blank[samepage] + \startlinecorrection[blank] + \useMPgraphic{dummy} + \stoplinecorrection + \egroup +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleZ #1#2#3 + \bgroup + \SampleHead{#1}{#2}{} + \blank[samepage] + #3 + \par + \egroup +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleA #1#2#3 + \StartSample{#1}{#2}{#3} + path p ; p := #3 ; % freeze randomized + if length(p)>0 : + DrawArrow p InRed ; + fi ; + drawpoints p InBetween ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleB #1#2#3#4 + \StartSample{#1}{#2}{#4} + DrawArrow (#3) InRed ; + DrawArrow (#4) InYellow ; + drawpoints (#3) InBetween ; + drawpoints (#4) InBetween ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleC #1#2#3#4 + \StartSample{#1}{#2}{#4} + path bb ; bb := boundingbox #3 ; + DrawArrow #3 InRed ; + draw #4 withpen pencircle scaled .15 InYellow ; + setbounds currentpicture to bb ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleD #1#2#3#4 + \StartSample{#1}{#2}{#4} + DrawArrow #3 InRed ; + setbounds currentpicture to #4 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleDD #1#2#3#4 + \StartSample{#1}{#2}{#4} + DrawArrow #3 InRed ; + DrawArrow #4 InYellow ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleE #1#2#3#4 + \StartSample{#1}{#2}{#4} + fill fullcircle scaled 1cm InRed ; + currentpicture := currentpicture #3 ; + Scale := 1 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleF #1#2#3#4 + \StartSample{#1}{#2}{#4} + DrawArrow #3 InRed ; + drawdot #4 InYellow ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleG #1#2#3#4 + \StartSample{#1}{#2}{#4} + draw #3 InRed ; + drawdot #4 InYellow ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleH #1#2#3#4#5 + \StartSample{#1}{#2}{#5} + DrawArrow #3 InRed ; + DrawArrow #4 InYellow ; + drawdot #5 InWhite ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleHH #1#2#3 + \StartSample{#1}{#2}{#3} + draw #3 InRed ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleI #1#2#3 + \StartSample{#1}{#2}{#3} + draw fullcircle InRed #3 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleII #1#2#3 + \StartSample{#1}{#2}{#3} + draw fullcircle #3 InRed ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleJ #1#2#3 + \StartSample{#1}{withpen #2}{withpen #3 scaled 2mm} + draw fullcircle xscaled 2 withpen #3 scaled Pen InRed ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleK #1#2#3 + \StartSample{#1}{withpen #2}{withpen #3} + draw fullcircle xscaled 2 withpen #3 InRed ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleL #1#2#3 + \StartSample{#1}{#2}{#2 #3} + #2 #3 InRed; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleM #1#2#3 + \StartSample{#1}{#2}{#2 #3} + fill boundingbox (#3--cycle) InRed ; + #2 #3 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleN #1#2#3#4 + \StartSample{#1}{#2}{#3} + #3 ; + draw #4 withpen pencircle scaled 25Pen InRed ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleO #1#2#3 + \StartSample{#1}{#2}{#3} + drawdot origin InRed ; + #3 scaled (2.5/Scale) InYellow ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleP #1#2#3 + \StartSample{#1}{#2}{#3} + drawdot origin InRed ; + #3 scaled (2.5/Scale) InYellow ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleQ #1#2#3 + \StartSample{#1}{#2}{#3} + #2 #3 withpen pencircle scaled 25Pen InRed ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleQQ #1#2#3 + \StartSample{#1}{#2}{#3} + #3 scaled (2.5/Scale) withpen pencircle scaled Pen InYellow ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleQQQ #1#2#3 + \StartSample{#1}{#2}{#3} + #3 scaled (2.5/Scale) withpen pencircle scaled Pen ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleR #1#2#3 + \StartSample{#1}{#2}{#3} + ColorCircle ; + addto currentpicture also (#3) shifted (bbwidth(currentpicture)+.1,0) ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleS #1#2#3 + \StartSample{#1}{#2}{#3} + Pen := Pen * Scale ; Scale := 1 ; #3 ;% + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleT #1#2#3#4 + \StartSample{#1}{#2}{#3} + #4 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleU #1#2#3 + \StartSample{#1}{#2}{#3} + Scale := Scale / 5 ; + #3 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleUU #1#2#3 + \StartSample{#1}{#2}{#3} + Scale := Scale / 10 ; + #3 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleV #1#2#3#4 + \StartSample{#1}{#2}{#3} + Scale := Scale / 5 ; + Pen := Pen * 20 ; + #4 ; + Pen := Pen / 20 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleW #1#2#3#4 + \StartSample{#1}{#2}{#3} + Scale := 1 ; + #4 ; + \StopSample +\stoptexdefinition + +\starttexdefinition unexpanded ShowSampleX #1#2#3 + \StartSample{#1}{#2}{#3} + #3 InRed ; + \StopSample +\stoptexdefinition + +\stopenvironment diff --git a/doc/context/sources/general/manuals/metafun/metafun-environment-screen.tex b/doc/context/sources/general/manuals/metafun/metafun-environment-screen.tex new file mode 100644 index 000000000..afeea7008 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-environment-screen.tex @@ -0,0 +1,139 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startenvironment mfun-environment-screen + +\enablemode[screen] + +\setuppapersize + [S6][S6] + +\setuplayout + [backspace=60pt, + topspace=60pt, + cutspace=0pt, + header=0pt, + footer=0pt, + bottom=20pt, + bottomdistance=40pt, + top=20pt, + topdistance=40pt, + leftmargin=30pt, + leftmargindistance=25pt, + rightmargin=0pt, + edge=0pt, + width=middle, + height=middle] + +\setupbodyfont + [9pt] + +\setuppagenumbering + [alternative=singlesided] + +\setupinteraction + [state=start, + style=bold, + color=darkred, + contrastcolor=darkred, + symbolset=navigation 3, + menu=on] + +\setupsymbolset + [navigation 3] + +\setupinteractionscreen + [option=max] + +\setupinteractionmenu + [bottom] + [unknownreference=yes, + state=start] + +\setuptoptexts + [] + [{\lightgray \bf Page \pagenumber + \doifcontent\quad{}{}\hbox{\getmarking[section]}}] + +\startinteractionmenu[bottom] + \txt \bf \lightgray \getmarking[chapter] \\ + \hfill + \bgroup + \setupinteraction[color=white,contrastcolor=white] + \got [CloseDocument] exit \\ + \egroup + \got [content] content \\ + \got [index] index \\ +% \got [commands] commands \\ + \got [reference] reference \\ + \setupinteraction[color=white,contrastcolor=white] + \got [PreviousJump] \symbol[PreviousJump] \\ + \got [previouspage] \symbol[previouspage] \\ + \got [nextpage] \symbol[nextpage] \\ + \got [NextJump] \symbol[NextJump] \\ +\stopinteractionmenu + +\starttexdefinition unexpanded ChapterCommand #1#2 + \framed [ + background=titled, + frame=off + ] { + #1 + \quad + #2 + } +\stoptexdefinition + +\startuseMPgraphic{PageFrame} + StartPage ; + save p, q, ranx, rany, minx, miny, maxx, maxy ; + pickup pencircle scaled 4pt ; + pair p[] ; path q[] ; numeric ranx, rany, minx, miny, maxx, maxy ; + minx := BackSpace/2 ; maxx := PaperWidth -minx ; ranx := minx/2 ; + miny := TopSpace /2 ; maxy := PaperHeight-miny ; rany := miny/2 ; + p[0] := llcorner Page ; + p[1] := (minx,0) randomshifted (ranx,0) ; + p[2] := (maxx,0) randomshifted (ranx,0) ; + p[3] := lrcorner Page ; + p[4] := (PaperWidth,miny) randomshifted (0,rany) ; + p[5] := (PaperWidth,maxy) randomshifted (0,rany) ; + p[6] := urcorner Page ; + p[7] := (maxx,PaperHeight) randomshifted (ranx,0) ; + p[8] := (minx,PaperHeight) randomshifted (ranx,0) ; + p[9] := ulcorner Page ; + p[10] := (0,maxy) randomshifted (0,rany) ; + p[11] := (0,miny) randomshifted (0,rany) ; + def page_color = (.4+uniformdeviate.3)*white enddef ; + fill Page withcolor \MPcolor{lightgray} ; + q[1] := p[9]--p[6]--p[ 5]--p[10]--cycle ; + q[2] := p[6]--p[3]--p[ 2]--p[ 7]--cycle ; + q[3] := p[3]--p[0]--p[11]--p[ 4]--cycle ; + q[4] := p[0]--p[9]--p[ 8]--p[ 1]--cycle ; + for i=1 upto 4: fill q[i] withcolor page_color ; endfor ; + q[1] := p[9]--p[8]--((p[8]--p[ 1]) intersectionpoint (p[10]--p[ 5]))--p[10]--cycle ; + q[2] := p[6]--p[5]--((p[5]--p[10]) intersectionpoint (p[ 2]--p[ 7]))--p[ 7]--cycle ; + q[3] := p[3]--p[4]--((p[4]--p[11]) intersectionpoint (p[ 7]--p[ 2]))--p[ 2]--cycle ; + q[4] := p[0]--p[1]--((p[1]--p[ 8]) intersectionpoint (p[ 4]--p[11]))--p[11]--cycle ; + for i=1 upto 4: fill q[i] withcolor page_color ; endfor ; + q[1] := p[ 8]--p[1] ; + q[2] := p[ 7]--p[2] ; + q[3] := p[10]--p[5] ; + q[4] := p[11]--p[4] ; + for i=1 upto 4: draw q[i] withcolor \MPcolor{darkred} ; endfor ; + StopPage ; +\stopuseMPgraphic + +% \setupbackgrounds[page][background=PageFrame] + +\setupbackgrounds + [page] + [background={PageFrame,backgraphics,foreground,foregraphics}] + +\defineoverlay[PageFrame][\useMPgraphic{PageFrame}] + +\startMPinclusions + background := \MPcolor{lightgray} ; +\stopMPinclusions + +\stopenvironment diff --git a/doc/context/sources/general/manuals/metafun/metafun-environment.tex b/doc/context/sources/general/manuals/metafun/metafun-environment.tex new file mode 100644 index 000000000..ca9fc24b3 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-environment.tex @@ -0,0 +1,595 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startenvironment metafun-environment + +\environment metafun-environment-layout + +\usemodule[abr-01,syntax] + +\startuseMPgraphic{cover page} + + numeric w ; w := PaperWidth -eps ; % or clip + numeric h ; h := PaperHeight-eps ; % or clip + + for i=0cm step 1cm until w : + for j=0cm step 1cm until h : + fill unitsquare scaled 1cm shifted (i,j) withcolor (.6+uniformdeviate.35)*white ; + endfor ; + endfor ; + + % clip currentpicture to unitsquare xyscaled (w,h) ; + + for i=0cm step 1cm until w+.5cm : + draw (i,0) -- (i,h) withpen pensquare scaled .5mm withcolor .625yellow ; + endfor ; + + for i=0cm step 1cm until h+.5cm : + draw (0,i) -- (w,i) withpen pensquare scaled .5mm withcolor .625yellow ; + endfor ; + +\stopuseMPgraphic + +\startuseMPgraphic{title page} + + StartPage ; + + \includeMPgraphic{cover page} + + picture p ; p := image (draw rawtextext("\darkred\definedfont[Sans]metafun" )) ; + picture q ; q := image (draw rawtextext("\darkred\definedfont[Sans]Hans Hagen")) ; + % picture r ; r := image (draw rawtextext("\darkred\definedfont[Sans]\doifnotmode{book}{context mkiv}")) ; + picture r ; r := image (draw rawtextext("\darkred\definedfont[Sans]context mkiv")) ; + + p := p xsized(PaperHeight - 2cm) ; + q := q xsized(PaperWidth - 8cm) ; + r := r xsized(6cm) ; + + p := p rotated 90 ; + r := r rotated 90 ; + + draw p shifted (urcorner Page - urcorner p - (1cm,1cm) - (-1mm,0) ) ; + draw q shifted (1cm, 1cm) ; + draw r shifted (urcorner Page - urcorner r - (5cm,2cm) ) ; + + StopPage ; + + setbounds currentpicture to Page ; + +\stopuseMPgraphic + +\startuseMPgraphic{back page} + + \includeMPgraphic{cover page} + +\stopuseMPgraphic + +\startuseMPgraphic{small grid} + + numeric w ; w := \overlaywidth ; + numeric h ; h := \overlayheight ; + numeric d ; d := .25cm ; + + drawoptions(withcolor (.6+uniformdeviate.35)*white) ; + + for i=0cm step d until w : + for j=0cm step d until h : + fill unitsquare scaled d shifted (i,j) ; + endfor ; + endfor ; + + drawoptions(withpen pencircle scaled .125mm withcolor .625yellow) ; + + for i=0 step d until w+d : draw (i,0) -- (i,h) ; endfor ; + for i=0 step d until h+d : draw (0,i) -- (w,i) ; endfor ; + +\stopuseMPgraphic + +\defineoverlay[title page][\useMPgraphic{title page}] + +\startnotmode[proof] + \defineoverlay[back page][\useMPgraphic{back page}] + \defineoverlay[small grid][\useMPgraphic{small grid}] +\stopnotmode + +% could be all in mp + +\starttexdefinition unexpanded OnGrid#1 + \hbox to \hsize \bgroup + \ifodd\realpageno + \hss + \fi + \setbox\scratchbox=\hbox { + \color[darkred]{#1} + } + \scratchoffset.25cm + \scratchwidth\wd\scratchbox + \ifdim\scratchwidth>\zeropoint + \advance \scratchwidth by .5\scratchoffset + \divide \scratchwidth by \scratchoffset + \multiply\scratchwidth by \scratchoffset + \advance \scratchwidth by 2\scratchoffset + \else + \scratchwidth8\scratchoffset + \fi + \dp\scratchbox \scratchoffset + \ht\scratchbox 2\scratchoffset + \framed [ + background=small grid, + frame=off, + offset=overlay + ] { + \hbox to \scratchwidth { + \hss + \box\scratchbox + \hss + } + } + \unless \ifodd\realpageno + \hss + \fi + \egroup +\stoptexdefinition + +\setupfootertexts + [margin] + [] + [\OnGrid{\doifelsetext{\getmarking[chapter]}{\getmarking[chapter]}{\getmarking[title]}}] + +\startuseMPgraphic{circled} + pickup pencircle scaled 1mm ; + drawoptions(withcolor (.6+uniformdeviate.35)*white) ; + fill fullcircle xscaled 1.5cm yscaled 1cm ; + drawoptions(withcolor .625yellow) ; + draw fullcircle xscaled 1.5cm yscaled 1cm ; +\stopuseMPgraphic + +\startnotmode[proof] + \defineoverlay[circled][\useMPgraphic{circled}] +\stopnotmode + +\starttexdefinition unexpanded Circled #1 + \framed [ + background=circled, + frame=off, + offset=overlay + ] { + \color[darkred]{#1} + } +\stoptexdefinition + +\setuppagenumbering + [location=] + +\setupheadertexts + [margin] + [][\hbox to \hsize{\hss\Circled\pagenumber\hss}] + +\setupheader + [style=bold] + +\setupfooter + [style=bold] + +\startuniqueMPgraphic{titled} + path p ; p := unitsquare xscaled OverlayWidth yscaled OverlayHeight ; + pickup pencircle scaled 1mm ; + drawoptions(withcolor .625yellow) ; + draw llcorner p -- lrcorner p ; + setbounds currentpicture to p ; +\stopuniqueMPgraphic + +\defineoverlay[titled][\uniqueMPgraphic{titled}] + +\starttexdefinition unexpanded ChapterCommand #1#2 + \ifconditional\headshownumber + \ifdim\leftmarginwidth<\rightmarginwidth + \donetrue + \else + \donefalse + \fi + \hskip-\ifdone\leftmargintotal\else\rightmargintotal\fi + \framed [ + background=titled, + frame=off, + offset=0pt + ] { + \hbox to \ifdone\leftmarginwidth\else\rightmarginwidth\fi { + #1 + \hss + } + \hskip\ifdone\leftmargindistance\else\rightmargindistance\fi + #2 + } + \else + \framed [ + background=titled, + frame=off, + offset=0pt + ] { + #2 + } + \fi +\stoptexdefinition + +\starttexdefinition unexpanded TitleCommand #1#2 + \framed [ + background=titled, + frame=off, + offset=0pt + ] { + #2 + } +\stoptexdefinition + +\starttexdefinition unexpanded IntroTitleCommand #1#2 + \framed [ + background=titled, + frame=off, + offset=0pt, + width=\textwidth + ] { + \hfill + #2 + } +\stoptexdefinition + +\starttexdefinition unexpanded ExtroTitleCommand #1#2 + \framed [ + background=titled, + frame=off, + offset=0pt, + width=\textwidth + ] { + \hss + #2 + \hss + } +\stoptexdefinition + +\setuphead + [chapter,section,subsection,subsubsection] + [color=darkred] + +\setuphead + [chapter] + [style=\bfc] + +\setuphead + [section] + [style=\bfa] + +\setuphead + [subsection] + [style=\bf] + +\setuphead + [subsubsection] + [style=\bf] + +\setuphead + [chapter,section,subsection,subsubsection] + [command=\ChapterCommand] + +\setuphead + [title,subject,subsubject,subsubsubject] + [command=\TitleCommand] + + +\definehead [introsubject] [subsubject] +\definehead [extrosubject] [subsubject] + +\setuphead [introsubject] [command=\IntroTitleCommand] +\setuphead [extrosubject] [command=\ExtroTitleCommand] + +\setuphead + [subsection,subsubject] + [before=\blank, + after=\blank] + +% charts + +\usemodule[chart] + +\setupFLOWcharts + [offset=0pt, + width=6\bodyfontsize, + height=3\bodyfontsize, + dx=\bodyfontsize, + dy=\bodyfontsize] + +\setupFLOWshapes + [framecolor=darkred] + +\setupFLOWlines + [color=darkyellow] + +% hm, slows down the whole doc + +\setupbackgrounds + [page] + [background={backgraphics,foreground,foregraphics}] + +\defineoverlay [backgraphics] [\positionoverlay{backgraphics}] +\defineoverlay [foregraphics] [\positionoverlay{foregraphics}] + +\startbuffer[shape-a] +\startuniqueMPgraphic{meta:hash}{linewidth,linecolor,angle,gap} + if unknown context_back : input mp-back ; fi ; + some_hash ( OverlayWidth, OverlayHeight , + \MPvar{linewidth}, \MPvar{linecolor} , + \MPvar{angle}, \MPvar{gap} ) ; +\stopuniqueMPgraphic +\stopbuffer + +\startbuffer[shape-b] +\setupMPvariables + [meta:hash] + [gap=.25\bodyfontsize, + angle=45, + linewidth=\overlaylinewidth, + linecolor=\overlaylinecolor] +\stopbuffer + +\startbuffer[shape-c] +\def\metahashoverlay#1{\uniqueMPgraphic{meta:hash}{angle=#1}} + +\defineoverlay[meta:hash:right] [\metahashoverlay{ +45}] +\defineoverlay[meta:hash:left] [\metahashoverlay{ -45}] +\defineoverlay[meta:hash:horizontal][\metahashoverlay{+180}] +\defineoverlay[meta:hash:vertical] [\metahashoverlay{ -90}] +\stopbuffer + +\startbuffer[symb-a] +\startuniqueMPgraphic{meta:button}{type,size,linecolor,fillcolor} + if unknown context_butt : input mp-butt ; fi ; + some_button ( \MPvar{type}, + \MPvar{size}, + \MPvar{linecolor}, + \MPvar{fillcolor} ) ; +\stopuniqueMPgraphic +\stopbuffer + +\startbuffer[symb-b] +\setupMPvariables + [meta:button] + [type=1, + size=2\bodyfontsize, + fillcolor=gray, + linecolor=darkred] +\stopbuffer + +\startbuffer[symb-c] +\def\metabuttonsymbol#1{\uniqueMPgraphic{meta:button}{type=#1}} + +\definesymbol[menu:left] [\metabuttonsymbol{101}] +\definesymbol[menu:right] [\metabuttonsymbol{102}] +\definesymbol[menu:list] [\metabuttonsymbol{103}] +\definesymbol[menu:index] [\metabuttonsymbol{104}] +\definesymbol[menu:person][\metabuttonsymbol{105}] +\definesymbol[menu:stop] [\metabuttonsymbol{106}] +\definesymbol[menu:info] [\metabuttonsymbol{107}] +\definesymbol[menu:down] [\metabuttonsymbol{108}] +\definesymbol[menu:up] [\metabuttonsymbol{109}] +\definesymbol[menu:print] [\metabuttonsymbol{110}] +\stopbuffer + +\hyphenation{tool-kit} + +\startbuffer[pagetext] +\subject{Edward R. Tufte} \input tufte \par +\subject{Donald E. Knuth} \input knuth \par +\subject{Douglas R. Hostadter} \input douglas \page +\stopbuffer + +\startbuffer[back-0] +\defineoverlay[page][\useMPgraphic{page}] +\setupbackgrounds[page][background=page] +\stopbuffer + +\startbuffer[back-1] +\startuseMPgraphic{page} + StartPage ; + path Main ; + if OnRightPage : + Main := lrcorner Field[OuterMargin][Text] -- + llcorner Field[Text] [Text] -- + ulcorner Field[Text] [Text] -- + urcorner Field[OuterMargin][Text] -- cycle ; + else : + Main := llcorner Field[OuterMargin][Text] -- + lrcorner Field[Text] [Text] -- + urcorner Field[Text] [Text] -- + ulcorner Field[OuterMargin][Text] -- cycle ; + fi ; + Main := Main enlarged 6pt ; + pickup pencircle scaled 2pt ; + fill Page withcolor .625white ; + fill Main withcolor .850white ; + draw Main withcolor .625red ; + StopPage ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[back-2] +\startuseMPgraphic{page} + StartPage ; + pickup pencircle scaled 2pt ; + fill Page withcolor .625white ; + fill Field[OuterMargin][Text] withcolor .850white ; + fill Field[Text] [Text] withcolor .850white ; + draw Field[OuterMargin][Text] withcolor .625red ; + draw Field[Text] [Text] withcolor .625red ; + StopPage ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[back-3] +\startuseMPgraphic{page} + StartPage ; + pickup pencircle scaled 2pt ; + fill Page withcolor .625white ; + fill Field[Text][Text] enlarged .5cm withcolor .850white ; + draw Field[Text][Text] enlarged .5cm withcolor .625red ; + StopPage ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[back-4] +\startuseMPgraphic{page} + StartPage ; + def somewhere = + (uniformdeviate 1cm,uniformdeviate 1cm) + enddef ; + path Main ; + Main := Field[Text][Text] lrmoved somewhere -- + Field[Text][Text] llmoved somewhere -- + Field[Text][Text] ulmoved somewhere -- + Field[Text][Text] urmoved somewhere -- cycle ; + pickup pencircle scaled 2pt ; + fill Page withcolor .625white ; + fill Main withcolor .850white ; + draw Main withcolor .625red ; + StopPage ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[back-4x] +\startuseMPgraphic{page} + StartPage ; + path Main ; Main := Field[Text][Text] randomized 1cm ; + pickup pencircle scaled 2pt ; + fill Page withcolor .625white ; + fill Main withcolor .850white ; + draw Main withcolor .625red ; + StopPage ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[back-5] +\startuseMPgraphic{page} + StartPage + for i=Top,Header,Text,Footer,Bottom : + for j=LeftEdge,LeftMargin,Text,RightMargin,RightEdge : + draw Field[i][j] withpen pencircle scaled 2pt withcolor .625red ; + endfor ; + endfor ; + StopPage +\stopuseMPgraphic +\stopbuffer + +\starttexdefinition unexpanded Literature #1#2#3 + \blank + \noindentation + #1 + \space + \begingroup + \bf + #2 + \endgroup + \space + #3 + \blank +\stoptexdefinition + +\environment metafun-environment-samples + +\startbuffer[handwrit] + +\usetypescript[serif][chorus] + +\definefont[SomeHandwriting][TeXGyreChorus-MediumItalic*default at 12pt] + +\start \SomeHandwriting\setstrut + +\startMPpage + StartPage ; + numeric l, n ; path p ; + l := 1.5LineHeight ; + n := 0 ; + p := origin shifted (l,0) -- origin shifted (PaperWidth-l,0) ; + for i=PaperHeight-l step -l until l : + n := n + 1 ; + fill p shifted (0,i+StrutHeight) -- + reverse p shifted (0,i-StrutDepth ) -- cycle + withcolor .85white ; + draw p shifted (0,i) + withpen pencircle scaled .25pt + withcolor .5white ; + draw p shifted (0,i+ExHeight) + withpen pencircle scaled .25pt + withcolor .5white ; + draw textext.origin("\strut How are those penalty lines called + in english? I may not steal candies ..." & decimal n) + shifted (l,i) + shifted (0,-StrutDepth) ; + endfor ; + StopPage ; +\stopMPpage +\stop +\stopbuffer + +\startbuffer[gridpage] +\startMPpage + StartPage ; + width := PaperWidth ; height := PaperHeight ; unit := cm ; + drawoptions(withpen pencircle scaled .2pt withcolor .8white) ; + draw vlingrid(0, width /unit, 1/10, width, height) ; + draw hlingrid(0, height/unit, 1/10, height, width ) ; + drawoptions(withpen pencircle scaled .5pt withcolor .4white) ; + draw vlingrid(0, width /unit, 1, width, height) ; + draw hlingrid(0, height/unit, 1, height, width ) ; + StopPage ; +\stopMPpage +\stopbuffer + +% needed to get white backgrounds + +\startmode[screen] + +\startbuffer[wipe] +picture savedpicture ; +savedpicture := currentpicture ; +currentpicture := nullpicture ; +draw savedpicture withcolor black ; +draw savedpicture ; +\stopbuffer + +\stopmode + +\startnotmode[screen] + +\startbuffer[wipe] + % nothing to whipe +\stopbuffer + +\stopnotmode + +\startbuffer[backtext] + + This document introduces you in the world of the graphic programming language + \MetaPost. Not only the language itself is covered in detail, but also the way to + interface with the typographic language \TeX. We also present the collection of + \MetaPost\ extensions that come with the \ConTeXt\ typesetting system. This + collection goes under the name \MetaFun. + + \blank + + All aspects of the \MetaPost\ language are covered. The first chapters focus on + the language itself, later chapters cover aspects like color, graphic + inclusions, adding labels, and stepwise constructing graphics. We finish with a + graphical overview of commands. + +\stopbuffer + +\startbuffer[backbanner] + + \WidthSpanningText + {PRAGMA Advanced Document Engineering, Hasselt NL, \currentdate[year]} + {\hsize} + {RegularBold} + +\stopbuffer + +\stopenvironment diff --git a/doc/context/sources/general/manuals/metafun/metafun-examples.tex b/doc/context/sources/general/manuals/metafun/metafun-examples.tex new file mode 100644 index 000000000..4e5e0eed3 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-examples.tex @@ -0,0 +1,3269 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-examples + +\environment metafun-environment + +\startchapter[title={A few applications}] + +\startintro + +For those who need to be inspired, we will demonstrate how \METAPOST\ can be used +to enhance your document with simple graphics. In these examples we will try to +be not too clever, simply because we lack the experience to be that clever. The +real tricks can be found in the files that come with \METAPOST. + +\stopintro + +\startsection[reference={sec:coils,sec:springs},title={Simple drawings}] + +In the words of John Hobby, the creator of \METAPOST, \quotation {\METAPOST\ is +particularly well||suited for generating figures for technical documents where +some aspects of a picture may be controlled by mathematical or geometrical +constraints that are best expressed symbolically. In other words, \METAPOST\ is +not meant to take the place of a freehand drawing tool or even an interactive +graphics editor}. + +An example of such a picture is the following one, which is dedicated to David +Arnold, who asked me once how to draw a spring. So, imagine that we want to draw +a schematic view of a system of four springs. + +\startbuffer[a] +def spring (expr a, b, w, h, n) = + ( ( (0,0) -- (0,h) -- + for i=1 upto n-1: (if odd(i) : - fi w/2,i+h) -- endfor + (0,n+h) -- (0,n+2h) ) + yscaled ((xpart (b-a) ++ ypart (b-a))/(n+2h)) + rotatedaround(origin,-90+angle(b-a)) + shifted a ) +enddef ; +\stopbuffer + +\startbuffer[b] +vardef spring (expr a, b, w, h, n) = + pair vec ; path pat ; numeric len ; numeric ang ; + vec := (b-a) ; + pat := for i=1 upto n-1: (if odd(i):-fi w/2,i)--endfor (0,n) ; + pat := (0,0)--(0,h)-- pat shifted (0,h)--(0,n+h)--(0,n+2h) ; + len := (xpart vec ++ ypart vec)/(n+2h) ; + ang := -90+angle(vec) ; + ( pat yscaled len rotatedaround(origin,ang) shifted a ) +enddef ; +\stopbuffer + +\startbuffer[c] +path p ; p := + (0,0)--spring((.5cm,0),(2.5cm,0),.5cm,0,10)--(3cm,0) ; + +draw p withpen pencircle scaled 2pt ; +draw p withpen pencircle scaled 1pt withcolor .8white; +\stopbuffer + +\startbuffer[d] +z1 = (+2cm,0) ; z2 = (0,+2cm) ; +z3 = (-2cm,0) ; z4 = (0,-2cm) ; + +pickup pencircle scaled 1.5pt ; + +drawoptions (withcolor .625red) ; + +draw spring (z1, z2, .75cm, 2, 10) ; draw z1 -- 1.5 z1 ; +draw spring (z2, z3, .75cm, 2, 9) ; draw z2 -- 1.1 z2 ; +draw spring (z3, z4, .75cm, 2, 8) ; draw z3 -- 1.5 z3 ; +draw spring (z4, z1, .75cm, 2, 7) ; draw z4 -- 1.1 z4 ; +\stopbuffer + +\startbuffer[e] +drawarrow + (0,0)--spring((.5cm,0),(2.5cm,0),.5cm,0,10)--(3cm,0) + withpen pencircle scaled 2pt withcolor .625red ; +\stopbuffer + +\startbuffer[f] +numeric u ; u := 1mm ; pickup pencircle scaled (u/2) ; +drawoptions (withcolor .625red) ; +draw (0,0)--spring((5u,0),(25u,0),5u,0,10)--(30u,0) ; +drawoptions (dashed evenly withcolor .5white) ; +draw (0,0)--spring((5u,0),(35u,0),(25/35)*5u,0,10)--(40u,0) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,d] +\stoplinecorrection + +A rather natural way to define such a system is: + +\typebuffer[d] + +Here, the macro \type {spring} takes 5~arguments: two points, the width of the +winding, the length of the connecting pieces, and the number of elements (half +windings). The definition of \type {spring} is less complicated than readable. + +\typebuffer[a] + +First we build a path starting in the origin, going left or right depending on +the counter being an odd number. + +\starttyping +pat := (0,0) ; +for i=1 upto n-1: + if odd(i) : + pat := pat -- (-w/2,i) ; + else : + pat := pat -- (+w/2,i) ; + fi ; +endfor ; +pat := pat -- (0,n) ; +\stoptyping + +Once you are accustomed to the way \METAPOST\ interprets (specialists may say +expand) the source code, you will start using \type {if} and \type {for} +statements in assignments. The previous code can be converted in a one liner, +using the pattern: + +\starttyping +pat := for i=1 upto n-1: (x,y)-- endfor (0,n) ; +\stoptyping + +The loop splits out a series of \type {(x,y)--} but the last point is added +outside the loop. Otherwise \type {pat} would have ended with a dangling \type +{--}. Of course we need to replace \type {(x,y)} by something meaningful, so we +get: + +\starttyping +pat := for i=1 upto n-1: (if odd(i):-fi w/2,i)--endfor (0,n) ; +\stoptyping + +We scale this path to the length needed. The expression $b-a$ calculates a +vector, starting at $a$ and ending at $b$. In \METAPOST, the expression \type +{a++b} is identical to $\sqrt{a^2+b^2}$. Thus, the expression \typ {xpart (b-a) +++ ypart (b-a)} calculates the length of the vector $b-a$. Because the unscaled +spring has length $n+2h$, scaling by the expression \typ {((xpart (b-a) ++ ypart +(b-a)) / (n+2h))} gives the spring the same length as the vector $b-a$. + +Because we have drawn our spring in the vertical position, we first rotate it 90 +degrees clockwise to a horizontal position, and then rotate it through an angle +equal to the angle in which the vector $b-a$ is pointing. After that, we shift it +to the first point. The main complications are that we also want to draw +connecting lines at the beginning and end, as well as support springs that +connect arbitrary points. Since no check is done on the parameters, you should be +careful in using this macro. + +When we want to improve the readability, we have to use intermediate variables. +Since the macro is expected to return a path, we must make sure that the content +matches this expectation. + +\typebuffer[b] + +If you use \type {vardef}, then the last statement is the return value. Here, +when \typ {p := spring (z1, z2, .75cm, 2, 10)} is being parsed, the macro is +expanded, the variables are kept invisible for the assignment, and the path at +the end is considered to be the return value. In a \type {def} the whole body of +the macro is \quote {pasted} in the text, while in a \type {vardef} only the last +line is visible. We will demonstrate this with a simple example. + +\starttyping +def one = (n,n) ; n := n+1 ; enddef ; +def two = n := n + 1 ; (n,n) enddef ; +\stoptyping + +Now, when we say: + +\starttyping +pair a, b ; numeric n ; n= 10 ; a := one ; b := two ; +\stoptyping + +we definitely get an error message. This is because, when macro \type {two} is +expanded, \METAPOST\ sees something: + +\starttyping +b := n := n + 1 ; +\stoptyping + +By changing the second definition in + +\starttyping +vardef two = n := n + 1 ; (n,n) enddef ; +\stoptyping + +the increment is expanded out of sight for \type {b :=} and the pair \type +{(n,n)} is returned. + +We can draw a slightly better looking spring by drawing twice with a different +pen. The following commands use the spring macro implemented by the \type +{vardef}. + +\typebuffer[c] + +This time we get: + +\startlinecorrection[blank] +\processMPbuffer[a,c] +\stoplinecorrection + +Since the \type {spring} macro returns a path, you can do whatever is possible +with a path, like drawing an arrow: + +\startlinecorrection[blank] +\processMPbuffer[a,e] +\stoplinecorrection + +Or even (watch how we use the neutral unit \type {u} to specify the dimensions): + +\startlinecorrection[blank] +\processMPbuffer[a,f] +\stoplinecorrection + +This was keyed in as: + +\typebuffer[e] + +and: + +\typebuffer[f] + +\stopsection + +\startsection[reference=sec:free labels,title={Free labels}] + +\index {labels} + +The \METAPOST\ label macro enables you to position text at certain points. This +macro is kind of special, because it also enables you to influence the +positioning. For that purpose it uses a special kind of syntax which we will not +discuss here in detail. + +\startbuffer[a] +pickup pencircle scaled 1mm ; +path p ; p := fullcircle scaled 3cm ; +draw p withcolor .625yellow ; +dotlabel.rt ("right" , point 0 of p) ; +dotlabel.urt ("upper right" , point 1 of p) ; +dotlabel.top ("top" , point 2 of p) ; +dotlabel.ulft ("upper left" , point 3 of p) ; +dotlabel.lft ("left" , point 4 of p) ; +dotlabel.llft ("lower left" , point 5 of p) ; +dotlabel.bot ("bottom" , point 6 of p) ; +dotlabel.lrt ("lower right" , point 7 of p) ; +\stopbuffer + +\typebuffer[a] + +The \type {label} command just typesets a text, while \type {dotlabel} also draws +a dot at the position of the label. The \type {thelabel} (not shown here) command +returns a picture. + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +There is a numeric constant \type {labeloffset} that can be set to influence the +distance between the point given and the content of the label. When we set the +offset to zero, we get the following output. + +\startbuffer[x] +interim labeloffset := 0pt ; % local assignment +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a] +\stoplinecorrection + +This kind of positioning works well as long as we know where we want the label to +be placed. However, when we place labels automatically, for instance in a macro, +we have to apply a few clever tricks. There are for sure many ways to accomplish +this goal, but here we will follow the mathless method. + +\startbuffer[a] +pickup pencircle scaled 1mm ; +path p ; p := fullcircle scaled 3cm ; +draw p withcolor .625yellow ; +vardef do (expr str) = + save currentpicture ; picture currentpicture ; + currentpicture := thelabel(str,origin) ; + draw boundingbox currentpicture withpen pencircle scaled .5pt ; + currentpicture +enddef ; +\stopbuffer + +\startbuffer[b] +dotlabel.rt (do("right") , point 0 of p) ; +dotlabel.urt (do("upper right") , point 1 of p) ; +dotlabel.top (do("top") , point 2 of p) ; +dotlabel.ulft (do("upper left") , point 3 of p) ; +dotlabel.lft (do("left") , point 4 of p) ; +dotlabel.llft (do("lower left") , point 5 of p) ; +dotlabel.bot (do("bottom") , point 6 of p) ; +dotlabel.lrt (do("lower right") , point 7 of p) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +The previous graphic visualizes the bounding box of the labels. This bounding box +is rather tight and therefore the placement of labels will always be suboptimal. +Compare the alignment of the left- and rightmost labels. The \type {btex}||\type +{etex} method is better, since then we can add struts, like: + +\starttyping +btex \strut right etex +\stoptyping + +to force labels with uniform depths and heights. The next graphic demonstrates +that this looks better indeed. Also, as \TEX\ does the typesetting we get the +current text font instead of the label font and the content will be properly +typeset; for instance kerning will be applied when applicable. Spending some time +on such details pays back in better graphics. + +\startbuffer[b] +dotlabel.rt (do(btex \strut right etex) , point 0 of p) ; +dotlabel.urt (do(btex \strut upper right etex) , point 1 of p) ; +dotlabel.top (do(btex \strut top etex) , point 2 of p) ; +dotlabel.ulft (do(btex \strut upper left etex) , point 3 of p) ; +dotlabel.lft (do(btex \strut left etex) , point 4 of p) ; +dotlabel.llft (do(btex \strut lower left etex) , point 5 of p) ; +dotlabel.bot (do(btex \strut bottom etex) , point 6 of p) ; +dotlabel.lrt (do(btex \strut lower right etex) , point 7 of p) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +Now, what happens when we want to place labels in other positions? In the worst +case, given that we place the labels manually, we end up in vague arguments in +favour for one or the other placement. + +\startbuffer[y] +p := p rotatedaround(center p, 22.5) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,y,b] +\stoplinecorrection + +Although any automatic mechanism will be sub||optimal, we can give it a try to +write a macro that deals with arbitrary locations. This macro will accept three +arguments and return a picture. + +\starttyping +thefreelabel("some string or picture",a position,the origin) +\stoptyping + +Our testcase is just a simple \type {for} loop that places a series of labels. +The \type {freedotlabel} macro is derived from \type {thefreelabel}. + +\startbuffer[c] +pickup pencircle scaled 1mm ; +path p ; p := fullcircle scaled 3cm ; +draw p withcolor .625yellow ; +for i=0 step .5 until 7.5 : + freedotlabel ("text" , point i of p, center p) ; +endfor ; +\stopbuffer + +\typebuffer[c] + +As a first step we will simply place the labels without any correction. We also +visualize the bounding box. + +\startbuffer[b] +vardef freedotlabel (expr str, loc, ori) = + drawdot loc ; draw thefreelabel(str,loc,ori) ; +enddef ; + +vardef freelabel (expr str, loc, ori) = + draw thefreelabel(str,loc,ori) ; +enddef ; +\stopbuffer + +\startbuffer[a] +vardef thefreelabel (expr str, loc, ori) = + save s ; picture s ; s := thelabel(str,loc) ; + draw boundingbox s withpen pencircle scaled .5pt ; + s +enddef ; +\stopbuffer + +\typebuffer[a] + +To make our lives more easy, we also define a macro that draws the dot as well as +a macro that draws the label. + +\typebuffer[b] + +Now we get: + +\startlinecorrection[blank] +\processMPbuffer[x,a,b,c] +\stoplinecorrection + +The original label macros permits us to align the label at positions, 4~corners +and 4~points halfway the sides. It happens that circles are also composed of +8~points. Because in most cases the label is to be positioned in the direction of +the center of a curve and the point at hand, it makes sense to take circles as +the starting points for positioning the labels. + +To help us in positioning, we define a special square path, \type {freesquare}. +This path is constructed out of 8~points that match the positions that are used +to align labels. + +\startbuffer[d] +path freesquare ; + +freesquare := ((-1,0)--(-1,-1)--(0,-1)--(+1,-1)-- + (+1,0)--(+1,+1)--(0,+1)--(-1,+1)--cycle) scaled .5 ; +\stopbuffer + +\typebuffer[d] + +We now show this free path together with a circle, using the following +definitions: + +\startbuffer[e] +drawpath fullcircle scaled 3cm ; +drawpoints fullcircle scaled 3cm ; +drawpointlabels fullcircle scaled 3cm ; +currentpicture := currentpicture shifted (5cm,0) ; +drawpath freesquare scaled 3cm ; +drawpoints freesquare scaled 3cm ; +drawpointlabels freesquare scaled 3cm ; +\stopbuffer + +\typebuffer[e] + +We use two drawing macros that are part of the suite of visual debugging macros. + +\startlinecorrection[blank] +\processMPbuffer[x,d,e] +\stoplinecorrection + +As you can see, point~1 is the corner point that suits best for alignment when a +label is put at point~1 of the circle. We will now rewrite \type {thefreelabel} +in such a way that the appropriate point of the associated \type {freesquare} is +found. + +\startbuffer[a] +vardef thefreelabel (expr str, loc, ori) = + save s, p, q, l ; picture s ; path p, q ; pair l ; + s := thelabel(str,loc) ; + p := fullcircle scaled (2*length(loc-ori)) shifted ori ; + q := freesquare xyscaled (urcorner s - llcorner s) ; + l := point (xpart (p intersectiontimes (ori--loc))) of q ; + draw q shifted loc withpen pencircle scaled .5pt ; + draw l shifted loc withcolor .625yellow ; + draw loc withcolor .625red ; + s +enddef ; +\stopbuffer + +\typebuffer[a] + +The macro xyscaled is part of \METAFUN\ and scales in two directions at once. The +\METAPOST\ primitive \type {intersectiontimes} returns a pair of time values of +the point where two paths intersect. The first part of the pair concerns the +first path. + +\startlinecorrection[blank] +\processMPbuffer[x,a,b,c] +\stoplinecorrection + +We are now a small step from the exact placement. If we change the last line of +the macro into: + +\starttyping +(s shifted -l) +\stoptyping + +we get the displacement we want. Although the final look and feel is also +determined by the text itself, the average result is quite acceptable. + +\startbuffer[a] +vardef thefreelabel (expr str, loc, ori) = + save s, p, q, l ; picture s ; path p, q ; pair l ; + s := thelabel(str,loc) ; + p := fullcircle scaled (2*length(loc-ori)) shifted ori ; + q := freesquare xyscaled (urcorner s - llcorner s) ; + l := point (xpart (p intersectiontimes (ori--loc))) of q ; + draw q shifted loc withpen pencircle scaled .5pt ; + draw l shifted loc withcolor .625yellow ; + draw loc withcolor .625red ; + (s shifted -l) +enddef ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,b,c] +\stoplinecorrection + +Because we also want to pass pictures, and add a bit of offset too, the final +implementation is slightly more complicated. The picture is handled with an +additional condition, and the offset with the \METAFUN\ macro \type {enlarged}. + +\startbuffer[a] +newinternal freelabeloffset ; freelabeloffset := 3pt ; + +vardef thefreelabel (expr str, loc, ori) = + save s, p, q, l ; picture s ; path p, q ; pair l ; + interim labeloffset := freelabeloffset ; + s := if string str : thelabel(str,loc) + else : str shifted -center str shifted loc fi ; + setbounds s to boundingbox s enlarged freelabeloffset ; + p := fullcircle scaled (2*length(loc-ori)) shifted ori ; + q := freesquare xyscaled (urcorner s - llcorner s) ; + l := point (xpart (p intersectiontimes (ori--loc))) of q ; + setbounds s to boundingbox s enlarged -freelabeloffset ; + (s shifted -l) +enddef ; +\stopbuffer + +\typebuffer[a] + +Watch how we temporarily enlarge the bounding box of the typeset label text. We +will now test this macro on a slightly rotated circle, using labels typeset by +\TEX. The \type {reverse} is there purely for cosmetic reasons, to suit the label +texts. + +\startbuffer[b] +pickup pencircle scaled 1mm ; +path p ; p := reverse fullcircle rotated -25 scaled 3cm ; +draw p withcolor .625yellow ; pair cp ; cp := center p ; +freedotlabel (btex \strut We can etex, point 0 of p, cp) ; +freedotlabel (btex \strut go on etex, point 1 of p, cp) ; +freedotlabel (btex \strut and on etex, point 2 of p, cp) ; +freedotlabel (btex \strut in etex, point 3 of p, cp) ; +freedotlabel (btex \strut defining etex, point 4 of p, cp) ; +freedotlabel (btex \strut funny etex, point 5 of p, cp) ; +freedotlabel (btex \strut macros. etex, point 6 of p, cp) ; +freedotlabel (btex \strut Can't we? etex, point 7 of p, cp) ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +\typebuffer[b] + +Unfortunately we can run into problems due to rounding errors. Therefore we use a +less readable but more safe expression for calculating the intersection points. +Instead of using point \type {loc} as endpoint we use \type {loc} shifted over a +very small distance into the direction \type {loc} from \type{ori}. In the +assignment to~\type {l} we replace \type {loc} by: + +\starttyping + ( (1+eps) * arclength(ori--loc) * unitvector(loc-ori) ) +\stoptyping + +\stopsection + +\startsection[title={Marking angles}] + +\index{angles} + +A convenient \METAPOST\ macro is \type {unitvector}. When we draw a line segment +from the origin to the point returned by this macro, the segment has a length of +1~base point. This macro has a wide range of applications, but some basic +knowledge of vector algebra is handy. The following lines of \METAPOST\ code +demonstrate the basics behind unitvectors. + +\startbuffer +pair uv ; pickup pencircle scaled 1mm ; autoarrows := true ; +draw fullcircle scaled 2cm withcolor .625red ; +for i=(10,35), (-40,-20), (85,-15) : + draw origin--i dashed evenly withcolor .625white ; + drawarrow origin--unitvector(i) scaled 1cm withcolor .625yellow ; +endfor ; +draw origin withcolor .625red ; +\stopbuffer + +\typebuffer + +The circle has a radius of 1cm, and the three line segments are drawn from the +origin in the direction of the points that are passed as arguments. Because the +vector has length of~1, we scale it to the radius to let it touch the circle. By +setting \type {autoarrows} we make sure that the arrowheads are scaled +proportionally to the linewidth of 1~mm. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +An application of this macro is drawing the angle between two lines. In the +\METAPOST\ manual you can find two macros for drawing angles: \type {mark_angle} +and \type {mark_rt_angle}. You may want to take a look at their definitions +before we start developing our own alternatives. + +\startbuffer[x] +pickup pencircle scaled 1mm ; autoarrows := true ; +drawoptions(withcolor .625white) ; +\stopbuffer + +\startbuffer[a] +def anglebetween (expr a, b) = + (unitvector(a){a rotated 90} .. unitvector(b)) +enddef ; +\stopbuffer + +\startbuffer[b] +pair a, b ; a := (2cm,-1cm) ; b := (3cm,1cm) ; +drawarrow origin--a ; drawarrow origin--b ; +drawarrow anglebetween(a,b) scaled 1cm withcolor .625red ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +The previous graphic demonstrates what we want to accomplish: a circular curve +indicating the angle between two straight lines. The lines and curve are drawn +with the code: + +\typebuffer[b] + +where \type {anglebetween} is defined as: + +\typebuffer[a] + +Both unitvectors return just a point on the line positioned 1~unit (later scaled +to 1cm) from the origin. We connect these points by a curve that starts in the +direction at the first point. If we omit the \type {a rotated 90} direction +specifier, we get: + +\startbuffer[a] +def anglebetween (expr a, b) = + (unitvector(a) .. unitvector(b)) +enddef ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +These definitions of \type {anglebetween} are far from perfect. If we don't start +in the origin, we get the curve in the wrong place and when we swap both points, +we get the wrong curve. + +\startbuffer[a] +def anglebetween (expr endofa, endofb, common, length) = + (unitvector (endofa-common){(endofa-common) rotated 90} .. + unitvector (endofb-common)) scaled length shifted common +enddef ; +\stopbuffer + +\startbuffer[b] +pair a, b, c ; a := (2cm,-1cm) ; b := (3cm,1cm) ; c := (-1cm,.5cm) ; +drawarrow c--a ; drawarrow c--b ; +drawarrow anglebetween(a,b,c,1cm) withcolor .625red ; +\stopbuffer + +The solution for the displacement is given in the \METAPOST\ manual and looks +like this (we package the macro a bit different): + +\typebuffer[a] + +As you can see, we compensate for the origin of both vectors. This macro is +called with a few more parameters. We need to pass the length, since we want to +add the shift to the macro and the shift takes place after the scaling. + +\typebuffer[b] + +That the results are indeed correct, is demonstrated by the output of following +example: + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +However, when we swap the points, we get: + +\startbuffer[a] +def anglebetween (expr endofb, endofa, common, length) = + (unitvector (endofa-common){(endofa-common) rotated 90} .. + unitvector (endofb-common)) scaled length shifted common +enddef ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +This means that instead of rotating over $90$ degrees, we have to rotate over +$-90$ or $270$ degrees. That way the arrow will also point in the other +direction. There are undoubtedly more ways to determine the direction, but the +following method also demonstrates the use of \type {turningnumber}, which +reports the direction of a path. For this purpose we compose a dummy cyclic path. + +\startbuffer[a] +vardef anglebetween (expr endofa, endofb, common, length) = + save tn ; tn := turningnumber(common--endofa--endofb--cycle) ; +show tn ; + (unitvector(endofa-common){(endofa-common) rotated (tn*90)} .. + unitvector(endofb-common)) scaled length shifted common +enddef ; +\stopbuffer + +\typebuffer[a] + +Because we use an intermediate variable, just to keep things readable, we have to +use \type {vardef} to hide the assignment for the outside world. We demonstrate +this macro using the following code: + +\startbuffer[b] +pair a, b, c ; a := (2cm,-1cm) ; b := (3cm,1cm) ; c := (-1cm,.5cm) ; +drawarrow c--a ; drawarrow c--b ; +drawarrow anglebetween(a,b,c,0.75cm) withcolor .625red ; +drawarrow anglebetween(b,a,c,1.50cm) withcolor .625red ; +\stopbuffer + +\typebuffer[b] + +Watch how both arrows point in the direction of the line that is determined by +the second point. + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +We now have the framework of an angle drawing macro ready and can start working +placing the label. + +\startbuffer[a] +vardef anglebetween (expr endofa, endofb, common, length, str) = + save curve, where ; path curve ; numeric where ; + where := turningnumber (common--endofa--endofb--cycle) ; + curve := (unitvector(endofa-common){(endofa-common) rotated (where*90)} + .. unitvector(endofb-common)) scaled length shifted common ; + draw thefreelabel(str,point .5 of curve,common) withcolor black ; + curve +enddef ; +\stopbuffer + +\typebuffer[a] + +The macro \type {thefreelabel} is part of \METAFUN\ and is explained in detail in +\in {section} [sec:free labels]. This macro tries to place the label as good as +possible without user interference. + +\startbuffer[b] +pair a ; a := (2cm,-1cm) ; drawarrow origin--a ; +pair b ; b := (3cm, 1cm) ; drawarrow origin--b ; +drawarrow + anglebetween(a,b,origin,1cm,btex $\alpha$ etex) + withcolor .625red ; +\stopbuffer + +\typebuffer[b] + +Instead of a picture we may also pass a string, but using \TEX\ by means of \type +{btex}||\type {etex} often leads to better results. + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +Because in most cases we want the length to be consistent between figures and +because passing two paths is more convenient than passing three points, the final +definition looks slightly different. + +\startbuffer[a] +numeric anglelength ; anglelength := 20pt ; + +vardef anglebetween (expr a, b, str) = % path path string + save endofa, endofb, common, curve, where ; + pair endofa, endofb, common ; path curve ; numeric where ; + endofa := point length(a) of a ; + endofb := point length(b) of b ; + if round point 0 of a = round point 0 of b : + common := point 0 of a ; + else : + common := a intersectionpoint b ; + fi ; + where := turningnumber (common--endofa--endofb--cycle) ; + curve := (unitvector (endofa-common){(endofa-common) rotated (where*90)} .. + unitvector (endofb-common)) scaled anglelength shifted common ; + draw thefreelabel(str,point .5 of curve,common) withcolor black ; + curve +enddef ; +\stopbuffer + +\typebuffer[a] + +This macro has a few more \type {if}'s than its predecessor. First we test if the +label is a string, and if so, we calculate the picture ourselves, otherwise we +leave this to the user. + +\startbuffer[b] +path a, b, c, d, e, f ; +a := origin--( 2cm, 1cm) ; b := origin--( 1cm, 2cm) ; +c := origin--(-2cm, 2cm) ; d := origin--(-2cm,-1cm) ; +e := origin--(-1cm,-2cm) ; f := origin--( 1cm,-2cm) ; +for i=a, b, c, d, e, f : drawarrow i ; endfor ; +anglelength := 1.0cm ; drawoptions(withcolor .625red) ; +drawarrow anglebetween(a,b,btex $\alpha $ etex) ; +drawarrow anglebetween(c,d,btex $\gamma $ etex) ; +drawarrow anglebetween(e,f,btex $\epsilon$ etex) ; +anglelength := 1.5cm ; drawoptions(withcolor .625yellow) ; +drawdblarrow anglebetween(b,c,btex $\beta $ etex) ; +drawarrow reverse anglebetween(d,e,btex $\delta $ etex) ; +drawarrow anglebetween(a,f,btex $\zeta $ etex) ; +\stopbuffer + +\typebuffer[b] + +Because \type {anglebetween} returns a path, you can apply transformations to it, +like reversing. Close reading of the previous code learns that the macro handles +both directions. + +\startlinecorrection[blank] +\processMPbuffer[x,a,b] +\stoplinecorrection + +Multiples of 90 degrees are often identified by a rectangular symbol. We will now +extend the previously defined macro in such a way that more types can be drawn. + +\startbuffer[a] +numeric anglelength ; anglelength := 20pt ; +numeric anglemethod ; anglemethod := 1 ; + +vardef anglebetween (expr a, b, str) = % path path string + save pointa, pointb, common, middle, offset ; + pair pointa, pointb, common, middle, offset ; + save curve ; path curve ; + save where ; numeric where ; + if round point 0 of a = round point 0 of b : + common := point 0 of a ; + else : + common := a intersectionpoint b ; + fi ; + pointa := point anglelength on a ; + pointb := point anglelength on b ; + where := turningnumber (common--pointa--pointb--cycle) ; + middle := ((common--pointa) rotatedaround (pointa,-where*90)) + intersectionpoint + ((common--pointb) rotatedaround (pointb, where*90)) ; + if anglemethod = 1 : + curve := pointa{unitvector(middle-pointa)}.. pointb; + middle := point .5 along curve ; + elseif anglemethod = 2 : + middle := common rotatedaround(.5[pointa,pointb],180) ; + curve := pointa--middle--pointb ; + elseif anglemethod = 3 : + curve := pointa--middle--pointb ; + elseif anglemethod = 4 : + curve := pointa..controls middle..pointb ; + middle := point .5 along curve ; + fi ; + draw thefreelabel(str, middle, common) withcolor black ; + curve +enddef ; +\stopbuffer + +\typebuffer[a] + +\startbuffer[p] +anglemethod := 1 ; +\stopbuffer + +\startbuffer[q] +anglemethod := 2 ; +\stopbuffer + +\startbuffer[r] +anglemethod := 3 ; +\stopbuffer + +\startbuffer +\startcombination[3*1] + {\processMPbuffer[x,a,p,b]} {method 1} + {\processMPbuffer[x,a,q,b]} {method 2} + {\processMPbuffer[x,a,r,b]} {method 3} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:three methods] + {Three ways of marking angles.} + {\getbuffer} + +\in {Figure} [fig:three methods] shows the first three alternative methods +implemented here. Instead of using \typ {unitvectors}, we now calculate the +points using the \typ {arctime} and \typ {arclength} primitives. Instead of +complicated expressions, we use the \METAFUN\ operators \type {along} and \type +{on}. The following expressions are equivalent. + +\starttyping +pointa := point anglelength on a ; +middle := point .5 along curve ; + +pointa := point (arctime anglelength of a) of a ; +middle := arctime (.5(arclength curve)) of curve) of curve ; +\stoptyping + +The third method can be implemented in different, more math intensive ways, but +the current implementation suits rather well and is understood by the author. + +\stopsection + +\startsection[reference=sec:color circles,title={Color circles}] + +\index{color} + +In \in {chapter} [sec:embedding] we showed a few color circles. Drawing such a +graphic can be done in several ways, and here we will show a few methods. First +we will demonstrate how you can apply \type {cutafter} and \type {cutbefore}, +next we will show how the \METAPOST\ macro \type {buildpath} can be used, and +finally we will present a clean solution using \type {subpath}. We will assume +that the circle is called with the macro: + +\starttyping +colorcircle (4cm, red, green, blue) ; +\stoptyping + +\startbuffer[circle] +vardef colorcircle (expr size, red, green, blue) = + save r, g, b, rr, gg, bb, cc, mm, yy ; + save b_r, b_g, g_r, g_b ; + save radius ; + + path r, g, b, rr, bb, gg, cc, mm, yy ; + pair b_r, b_g, g_r, g_b ; + + numeric radius ; radius := 3cm ; + + pickup pencircle scaled (radius/20) ; + + r := g := b := fullcircle scaled radius shifted (0,radius/4); + + r := r rotatedaround(origin, 15) ; % drawarrow r withcolor red ; + g := g rotatedaround(origin,135) ; % drawarrow g withcolor green ; + b := b rotatedaround(origin,255) ; % drawarrow b withcolor blue ; + + b_r := b intersectionpoint r ; % draw b_r ; + b_g := b intersectionpoint g ; % draw b_g ; + g_r := reverse g intersectionpoint r ; % draw g_r ; + g_b := reverse g intersectionpoint b ; % draw g_b ; + + bb := b cutafter b_r ; bb := bb cutbefore b_g ; % drawarrow bb ; + gg := g cutbefore b_g ; gg := gg cutafter g_r ; % drawarrow gg ; + rr := r cutbefore g_r & r cutafter b_r ; % drawarrow rr ; + + cc := b cutbefore b_r ; cc := cc cutafter g_b ; % drawarrow br ; + yy := g cutbefore g_r ; yy := yy cutafter g_b ; % drawarrow rg ; + mm := r cutbefore g_r & r cutafter b_r ; % drawarrow gb ; + + bb := gg -- rr -- reverse bb -- cycle ; + gg := bb rotatedaround(origin,120) ; + rr := bb rotatedaround(origin,240) ; + + cc := mm -- cc -- reverse yy -- cycle ; + yy := cc rotatedaround(origin,120) ; + mm := cc rotatedaround(origin,240) ; + + fill fullcircle scaled radius withcolor white ; + + fill rr withcolor red ; fill cc withcolor white-red ; + fill gg withcolor green ; fill mm withcolor white-green ; + fill bb withcolor blue ; fill yy withcolor white-blue ; + + for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ; + + currentpicture := currentpicture xsized size ; +enddef ; +\stopbuffer + +We need to calculate seven paths. The first implementation does all the handywork +itself and thereby is rather long, complicated and unreadable. It does not really +use the strength of \METAPOST\ yet. + +\typebuffer[circle] + +In determining the right intersection points, you need to know where the path +starts and in what direction it moves. In case of doubt, drawing the path as an +arrow helps. If you want to see the small paths used, you need to comment the +lines with the \type {fill}'s and uncomment the lines with \type {draw}'s. Due to +the symmetry and the fact that we keep the figure centered around the origin, we +only need to calculate two paths since we can rotate them. + +There are for sure more (efficient) ways to draw such a figure, but this one +demonstrates a few new tricks, like grouping. We use grouping here because we +want to use \type {mm} to indicate the magenta path, and \type {mm} normally +means millimeter. Within a group, you can save variables. These get their old +values when the group is left. + +With \type {for} we process multiple paths after each other. In this case it +hardly saves tokens, but it looks more clever. + +One of the more efficient methods is using the \type {buildcycle} macro. This +macro takes two or more paths and calculates the combined path. Although this is +a rather clever macro, you should be prepared to help it a bit when paths have +multiple intersection points. Again, we could follow a more secure mathematical +method, but the next one took only a few minutes of trial and error. To save some +memory, we redefine the \type {colors} graphic. + +\startbuffer[demo] +colorcircle(4cm, red, green, blue) ; +\stopbuffer + +When we call this macro as: + +\typebuffer[demo] + +we get: + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +Of course this macro is only used for demonstration purposes and has no real use. + +\startbuffer[circle] +vardef colorcircle (expr size, red, green, blue) = + save r, g, b, rr, gg, bb, cc, mm, yy ; save radius ; + path r, g, b, rr, bb, gg, cc, mm, yy ; numeric radius ; + + radius := 5cm ; pickup pencircle scaled (radius/25) ; + + r := g := b := fullcircle scaled radius shifted (0,radius/4) ; + + r := r rotatedaround (origin, 15) ; + g := g rotatedaround (origin,135) ; + b := b rotatedaround (origin,255) ; + + r := r rotatedaround(center r,-90) ; + g := g rotatedaround(center g, 90) ; + + gg := buildcycle(buildcycle(reverse r,b),g) ; + cc := buildcycle(buildcycle(b,reverse g),r) ; + + rr := gg rotatedaround(origin,120) ; + bb := gg rotatedaround(origin,240) ; + + yy := cc rotatedaround(origin,120) ; + mm := cc rotatedaround(origin,240) ; + + fill fullcircle scaled radius withcolor white ; + + fill rr withcolor red ; fill cc withcolor white-red ; + fill gg withcolor green ; fill mm withcolor white-green ; + fill bb withcolor blue ; fill yy withcolor white-blue ; + + for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ; + + currentpicture := currentpicture xsized size ; +enddef ; +\stopbuffer + +\typebuffer [circle] + +Since we don't want to duplicate a graphic, this time we show the dark +alternatives. + +\startbuffer[demo] +colorcircle(4cm, .5red, .5green, .5blue) ; +\stopbuffer + +\typebuffer[demo] + +This kind of unsafe path calculations are very sensitive to breaking. Changing +the \type {radius/4} into something else demonstrates this but we will not +challenge this macro that much. Therefore, the 50\% color circle shows up as: + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +This command is part of \METAFUN\ and can be used to determine nice color +combinations by also looking at their complementary colors. + +\startbuffer[demo] +colorcircle (4cm, .7red, .5green, .3blue) ; +\stopbuffer + +\typebuffer[demo] + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +The next circle that we draw shows the three main colors used in this document. +This circle is not that beautiful. + +\startbuffer[demo] +colorcircle(4cm,.625red,.625yellow,.625white) ; +\stopbuffer + +\typebuffer[demo] + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +This definition can be cleaned up a bit by using \type {transform}, but the fuzzy +\type {buildcycle}'s remain. + +\startbuffer[circle] +vardef colorcircle (expr size, red, green, blue) = + save r, g, b, rr, gg, bb, cc, mm, yy ; save radius ; + path r, g, b, rr, bb, gg, cc, mm, yy ; numeric radius ; + + radius := 5cm ; pickup pencircle scaled (radius/25) ; + + transform t ; t := identity rotatedaround(origin,120) ; + + r := fullcircle scaled radius + shifted (0,radius/4) rotatedaround(origin,15) ; + + g := r transformed t ; b := g transformed t ; + + r := r rotatedaround(center r,-90) ; + g := g rotatedaround(center g, 90) ; + + gg := buildcycle(buildcycle(reverse r,b),g) ; + cc := buildcycle(buildcycle(b,reverse g),r) ; + + rr := gg transformed t ; bb := rr transformed t ; + yy := cc transformed t ; mm := yy transformed t ; + + fill fullcircle scaled radius withcolor white ; + + fill rr withcolor red ; fill cc withcolor white-red ; + fill gg withcolor green ; fill mm withcolor white-green ; + fill bb withcolor blue ; fill yy withcolor white-blue ; + + for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ; + + currentpicture := currentpicture xsized size ; +enddef ; +\stopbuffer + +\typebuffer [circle] + +\startbuffer[demo] +colorcircle(4cm,(.4,.6,.8),(.8,.4,.6),(.6,.8,.4)); +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +This rather nice circle is defined as: + +\typebuffer[demo] + +The final implementation, which is part of \METAFUN, is slightly more efficient. + +\startbuffer[circle] +vardef colorcircle (expr size, red, green, blue) = + save r, g, b, c, m, y, w ; save radius ; + path r, g, b, c, m, y, w ; numeric radius ; + + radius := 5cm ; pickup pencircle scaled (radius/25) ; + + transform t ; t := identity rotatedaround(origin,120) ; + + r := fullcircle rotated 90 scaled radius + shifted (0,radius/4) rotatedaround(origin,135) ; + + b := r transformed t ; g := b transformed t ; + + c := buildcycle(subpath(1,7) of g, subpath(1,7) of b) ; + y := c transformed t ; m := y transformed t ; + + w := buildcycle(subpath(3,5) of r, + subpath(3,5) of g, subpath(3,5) of b) ; + + pushcurrentpicture ; + + fill r withcolor red ; + fill g withcolor green ; + fill b withcolor blue ; + fill c withcolor white-red ; + fill m withcolor white-green ; + fill y withcolor white-blue ; + fill w withcolor white ; + + for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ; + + currentpicture := currentpicture xsized size ; + + popcurrentpicture ; +enddef ; +\stopbuffer + +\typebuffer [circle] + +Here, we first fill the primary circles, next we fill the secondary ones. These +also cover the center, which is why finally we fill the center with white. + +\startbuffer[demo] +colorcircle(4cm,(.2,.5,.8),(.8,.2,.5),(.5,.8,.2)); +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +The circle uses the following colors: + +\typebuffer[demo] + +The next graphic demonstrates how the subpaths look that build the shapes. + +\startbuffer[circle] +vardef colorcircle (expr size, red, green, blue) = + save r, g, b, c, m, y, w ; save radius ; + path r, g, b, c, m, y, w ; numeric radius ; + + radius := 5cm ; pickup pencircle scaled (radius/25) ; + + transform t ; t := identity rotatedaround(origin,120) ; + + r := fullcircle rotated 90 scaled radius + shifted (0,radius/4) rotatedaround(origin,135) ; + + b := r transformed t ; g := b transformed t ; + + c := buildcycle(subpath(1,7) of g,subpath(1,7) of b) ; + y := c transformed t ; m := y transformed t ; + + w := buildcycle(subpath(3,5) of r, + subpath(3,5) of g, subpath(3,5) of b) ; + + pushcurrentpicture ; + + def do_it = + fill r withcolor red ; + fill g withcolor green ; + fill b withcolor blue ; + fill c withcolor white-red ; + fill m withcolor white-green ; + fill y withcolor white-blue ; + fill w withcolor white ; + for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ; + enddef ; + + autoarrows := true ; + + do_it ; + for i=r,g,b : drawarrow i withcolor black ; endfor ; + currentpicture := currentpicture shifted (-2radius,0) ; + + do_it ; + for i=r,g,b : drawarrow subpath(1,7) of i withcolor black ; endfor ; + currentpicture := currentpicture shifted (-2radius,0) ; + + do_it ; + for i=r,g,b : drawarrow subpath(3,5) of i withcolor black ; endfor ; + currentpicture := currentpicture shifted (+4radius,2radius) ; + + drawarrow r withpen pencircle scaled (radius/10) withcolor red ; + drawarrow g withpen pencircle scaled (radius/20) withcolor green ; + drawarrow b withpen pencircle scaled (radius/40) withcolor blue ; + currentpicture := currentpicture shifted (-2radius,0) ; + + drawarrow c withpen pencircle scaled (radius/10) withcolor white-red ; + drawarrow m withpen pencircle scaled (radius/20) withcolor white-green ; + drawarrow y withpen pencircle scaled (radius/40) withcolor white-blue ; + currentpicture := currentpicture shifted (-2radius,0) ; + + drawarrow w withcolor black ; + + currentpicture := currentpicture xsized 3size ; + + popcurrentpicture ; +enddef ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[circle,demo] +\stoplinecorrection + +We did not mention what the push and pop commands are responsible for. Scaling +the current picture is well defined as long as we deal with one graphic. However, +if the current picture already has some content, this content is also scaled. The +push and pop commands let us add content to the current picture as well as +manipulating the picture as a whole without any side effects. The final result is +put on top of the already drawn content. Instead of the sequence: + +\starttyping +pushcurrentpicture ; + ... + currentpicture := currentpicture ... transformations ... ; +popcurrentpicture ; +\stoptyping + +you can say: + +\starttyping +pushcurrentpicture ; + ... +popcurrentpicture ... transformations ... ; +\stoptyping + +Both are equivalent to: + +\starttyping +draw image ( ... ) ... transformations ... ; +\stoptyping + +For larger sequences of commands, the push||pop alternative gives a bit more more +readable code. + +\stopsection + +\startsection[title={Fool yourself}] + +When doing a literature search on the human perception of black||white edges, I +ran into several articles with graphics that I remember having seen before in +books on psychology, physiology and|/|or ergonomics. One of the articles was by +Edward H.~Adelson of MIT and we will use a few of his example graphics in our +exploration to what extend \METAPOST\ can be of help in those disciplines. Since +such graphics normally occur in typeset documents, we will define them in the +document source. + +\startbuffer[a] +\startbuffer +interim linecap := butt ; numeric u ; u := 1cm ; +pickup pencircle scaled .5u ; +for i=1u step u until 5u : + draw (0,i) -- (5u,i) ; +endfor ; +for i=2u step u until 4u : + draw (u,i) -- (2u,i) withcolor .5white ; + draw ((3u,i) -- (4u,i)) shifted (0,-.5u) withcolor .5white ; +endfor ; +\stopbuffer +\stopbuffer + +\startbuffer[b] +\placefigure + [here][fig:tricked 1] + {White's illusion.} + {\processMPbuffer} +\stopbuffer + +\getbuffer[a,b] + +Unless you belong to the happy few whose visual capabilities are not distorted by +neural optimizations, in \in {figure} [fig:tricked 1] the gray rectangles at the +left look lighter than those on the right. Alas, you can fool yourself, but +\METAPOST\ does not cheat. This graphic, referred to as White's illusion, is +defined as follows. + +\typebuffer[a] + +Watch how we include the code directly. We have packaged this graphic in a buffer +which we include as a floating figure. + +\typebuffer[b] + +When passed to \METAPOST, this code is encapsulated in its \type {beginfig} and +\type {endfig} macros and thereby grouped. But any change to a variable that is +not explicitly saved, migrates to the outer level. In order to prevent all +successive graphics to have butt'd linecaps, we have to change this line +characteristic locally. Because \type {linecap} is defined as an internal +variable, we have to use \type {interim} to overload its value. Because \type {u} +is a rather commonly used scratch variable, we don't save its value. + +Watch how we use \type {u} as the loop step. In spite of what your eyes tell you, +this graphic only has two explicit color directives, both being 50\% black. In +the next example we will use some real colors. + +\startbuffer[a] +\startuseMPgraphic{first} + numeric size, delta ; + size := 2.5cm ; delta := size/3 ; + color mainshade, topshade, bottomshade, centershade ; + mainshade := \MPcolor{funcolor} ; + topshade := .9mainshade ; bottomshade := .5mainshade ; + centershade := .5[topshade,bottomshade] ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[b] +\startuseMPgraphic{second} + \includeMPgraphic{first} + fill fullsquare scaled size withcolor topshade ; + fill fullsquare scaled delta withcolor centershade ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[c] +\startuseMPgraphic{third} + \includeMPgraphic{first} + fill fullsquare scaled size withcolor bottomshade ; + fill fullsquare scaled delta withcolor centershade ; +\stopuseMPgraphic +\stopbuffer + +\getbuffer[a,b,c] + +\startbuffer[d] +\startcombination[5*2] + {\definecolor[funcolor][red] \useMPgraphic{second}} {} + {\definecolor[funcolor][green] \useMPgraphic{second}} {} + {\definecolor[funcolor][blue] \useMPgraphic{second}} {} + {\definecolor[funcolor][yellow]\useMPgraphic{second}} {} + {\definecolor[funcolor][white] \useMPgraphic{second}} {} + {\definecolor[funcolor][red] \useMPgraphic{third}} {} + {\definecolor[funcolor][green] \useMPgraphic{third}} {} + {\definecolor[funcolor][blue] \useMPgraphic{third}} {} + {\definecolor[funcolor][yellow]\useMPgraphic{third}} {} + {\definecolor[funcolor][white] \useMPgraphic{third}} {} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:tricked 2] + {The simultaneous contrast effect.} + {\getbuffer[d]} + +In \in {figure} [fig:tricked 2] the small squares in the center of each colored +pair of big squares have the same shade, but the way we perceive them are +influenced by their surroundings. Both sets of squares are defined using usable +graphics. The top squares are defined as: + +\typebuffer[b] + +and the bottom squares are coded as: + +\typebuffer[c] + +Because both graphics share code, we have defined that code as a separate +graphic, that we include. The only point of interest in this definition is the +fact that we let \METAPOST\ interpolate between the two colors using \type {.5[ +]}. + +\typebuffer[a] + +The color \type {funcolor} is provided by \CONTEXT, and since we want to use this +graphic with different colors, this kind of mapping is quite convenient. The +bunch of graphics is packaged in a combination with empty captions. Note how we +set the color before we include the graphic. + +\typebuffer[d] + +We use a similar arrangement for the following graphic, where we have replaced +the definitions of \type {first}, \type {second} and \type {third} by new +definitions. + +\startbuffer[a] +\startuseMPgraphic{first} + numeric height, width, radius, gap ; gap := 1mm ; + height = 2.5cm ; width := height/2 ; radius := height/2.5 ; + color mainshade, leftshade, rightshade, centershade ; + mainshade := \MPcolor{funcolor} ; + leftshade := .9mainshade ; rightshade := .5mainshade ; + centershade := .5[leftshade,rightshade] ; + fill unitsquare xyscaled ( width,height) withcolor leftshade ; + fill unitsquare xyscaled (-width,height) withcolor rightshade ; + draw (fullcircle scaled radius) shifted (0,height/2) + withpen pencircle scaled (radius/2) withcolor centershade ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[b] +\startuseMPgraphic{second} + \includeMPgraphic{first} + interim linecap := butt ; pickup pencircle scaled gap ; + draw (0,0) -- (0,height) withcolor white ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[c] +\startuseMPgraphic{third} + \includeMPgraphic{first} + picture p, q ; p := q := currentpicture ; + clip p to unitsquare xscaled width yscaled height ; + clip q to unitsquare xscaled -width yscaled height ; + currentpicture := p ; + addto currentpicture also q shifted (0,radius/2) ; +\stopuseMPgraphic +\stopbuffer + +\getbuffer[a,b,c] + +\startbuffer[d] +\startcombination[5*3] + {\definecolor[funcolor][red] \useMPgraphic{first}} {} + {\definecolor[funcolor][green] \useMPgraphic{first}} {} + {\definecolor[funcolor][blue] \useMPgraphic{first}} {} + {\definecolor[funcolor][yellow]\useMPgraphic{first}} {} + {\definecolor[funcolor][white] \useMPgraphic{first}} {} + {\definecolor[funcolor][red] \useMPgraphic{second}} {} + {\definecolor[funcolor][green] \useMPgraphic{second}} {} + {\definecolor[funcolor][blue] \useMPgraphic{second}} {} + {\definecolor[funcolor][yellow]\useMPgraphic{second}} {} + {\definecolor[funcolor][white] \useMPgraphic{second}} {} + {\definecolor[funcolor][red] \useMPgraphic{third}} {} + {\definecolor[funcolor][green] \useMPgraphic{third}} {} + {\definecolor[funcolor][blue] \useMPgraphic{third}} {} + {\definecolor[funcolor][yellow]\useMPgraphic{third}} {} + {\definecolor[funcolor][white] \useMPgraphic{third}} {} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:tricked 3] + {Koffka's examples of manipulating contrast by changing + the spatial configuration.} + {\getbuffer[d]} + +The definition of the first row of \in {figure} [fig:tricked 3] is used in the +second and third and therefore is the most complicated. We use quite some scratch +variables to reach a high level of abstraction. The \type {xyscaled} operator is +a \METAFUN\ macro. + +\typebuffer[a] + +The graphics of the second row extends those of the first by drawing a white line +through the middle. In this example setting the linecap is not really needed, +because rounded top and bottoms in white are invisible and the part that extends +beyond the points does not count in calculating the bounding box. + +\typebuffer[b] + +The third row graphics again extend the first graphic. First we copy the picture +constructed so far. Watch the double assignment. Next we clip the pictures in +half, and shift the right half down over the width of the circle. + +\typebuffer[c] + +\stopsection + +% \startsection[title={Puzzles}] +% +% {\em Maybe.} +% +% \stopsection +% +% \startsection[title={Flow charts}] +% +% {\em Instead of starting anew every time, you can use predefined macros, like +% those in the flow chart module. Let's see how we can influence the \METAPOST\ +% code. Maybe not here.} +% +% \stopsection +% +% \startsection[title={Chemistry}] +% +% {\em \METAPOST\ can do it's work unseen, as in the chemistry module that comes +% with \CONTEXT. There, \METAPOST\ is used as one of the graphical plug||ins. It +% demonstrates that we can put \METAPOST\ to work without seeing any code.} +% +% \stopsection + +\startsection[title={Growing graphics}] + +Although \METAPOST\ is not really suited as a simulation engine, it is possible +to build graphics that are built and displayed incrementally with a sequence of +mouse clicks. The following example is the result of an email discussion David +Arnold and the author had while \METAFUN\ evolved. + +Instead of defining the graphics in a separate \METAPOST\ file, we will +incorporate them in the document source in which they are used. We can use +several methods. + +\startitemize[n] +\startitem + Define macros and figures in a separate file and include the graphics as + external graphics. +\stopitem +\startitem + Define everything in the document source as usable graphics and include the + graphics using \type {\useMPgraphic}. +\stopitem +\startitem + Package the graphic components in buffers and paste those together as + graphics that can be processed at run time. +\stopitem +\stopitemize + +The first method is the most independent one, which has its advantages if we want +to use the graphics in other applications too. The second method works well in +graphics where parts of the definitions change between invocations of the +graphic. This method follows the template: + +\starttyping +\startuseMPgraphic{whatever} + ... +\stopuseMPgraphic + +\startuseMPgraphic{result} + ... + \includeMPgraphic{whatever} + ... +\stopuseMPgraphic + +\useMPgraphic{result} +\stoptyping + +The disadvantage of this method is that it cannot be combined with \type +{btex}||\type {etex} since it is nearly impossible to determine when, how, and to +what extent the content of a graphic should be expanded before writing it to the +temporary \METAPOST\ file. + +Therefore, we will demonstrate how buffers can be used. This third method closely +parallels the first way of defining graphics. A nice side effect is that we can +easily typeset these buffers verbatim, which we did to typeset this document. + +We are going to do a classic compass and straightedge construction, the bisection +of a line segment joining two arbitrary points. We will construct five graphics, +where each one displays one step of the construction. We will embed each graphic +in a start||stop command. Later we will see the advantage of this strategy. + +\startbuffer +\startbuffer[a] +def start_everything = enddef ; +def stop_everything = enddef ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\startbuffer[b] +numeric u, w ; u := .5cm ; w := 1pt ; + +pickup pencircle scaled w ; + +def draw_dot expr p = + draw p withpen pencircle scaled 3w ; +enddef ; + +def stand_out = + drawoptions(withcolor .625red) ; +enddef ; +\stopbuffer +\stopbuffer + +We are going to draw a few dots, and to force consistency we first define a macro +\type {draw_dot}. The current step will be highlighted in red using \type +{stand_out}. + +\typebuffer \getbuffer + +\startbuffer +\startbuffer[c] +def draw_basics = + pair pointA, pointB ; path lineAB ; + pointA := origin ; pointB := pointA shifted (5u,0) ; + lineAB := pointA -- pointB ; + draw lineAB ; + draw_dot pointA ; label.lft(btex A etex, pointA) ; + draw_dot pointB ; label.rt (btex B etex, pointB) ; +enddef ; +\stopbuffer +\stopbuffer + +First, we construct the macro that will plot two points $A$ and $B$ and connect +them with a line segment. + +\typebuffer \getbuffer + +\startbuffer +\startbuffer[1] +start_everything ; + stand_out ; draw_basics ; +stop_everything ; +\stopbuffer +\stopbuffer + +The code in this buffer executes the preceding macros. The \type {..._everything} +commands are still undefined, but later we can use these hooks for special +purposes. + +\typebuffer \getbuffer + +This graphic can now be embedded by the \CONTEXT\ command +\type {\processMPbuffer}. This command, like the ordinary +buffer inclusion commands, accepts a list of buffers. + +\startbuffer +\startlinecorrection[blank] +\ruledhbox{\processMPbuffer[a,b,c,1]} +\stoplinecorrection +\stopbuffer + +\typebuffer + +We use \type {\ruledhbox} to show the tight bounding box of the graphic. The line +correction takes care of proper spacing around non textual content, like +graphics. \footnote {These spacing commands try to get the spacing around the +content visually compatible, and take the height and depth of the preceding and +following text into account.} This is only needed when the graphic is part of the +text flow! + +\getbuffer + +Next, we draw two circles of equal radius, one centered at point $A$, the other +at point $B$. + +\startbuffer +\startbuffer[d] +def draw_circles = + path circleA, circleB ; numeric radius, distance ; + distance := (xpart pointB) - (xpart pointA) ; + radius := 2/3 * distance ; + circleA := fullcircle scaled (2*radius) ; + circleB := circleA shifted pointB ; + draw circleA ; + draw circleB ; +enddef ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\startbuffer[2] +start_everything ; + draw_basics ; stand_out ; draw_circles ; +stop_everything ; +\stopbuffer +\stopbuffer + +As you can see, we move down the \type {stand_out} macro so that only the +additions are colored red. + +\typebuffer \getbuffer + +We now use \type{\processMPbuffer[a,b,c,d,2]} to include the latest step. + +\startlinecorrection[blank] +\ruledhbox{\processMPbuffer[a,b,c,d,2]} +\stoplinecorrection + +The next step in the construction of the perpendicular bisector requires that we +find and label the points of intersection of the two circles centered at points +$A$ and $B$. The intersection points are calculated as follows. Watch the \type +{reverse} operation, which makes sure that we get the second intersection point. + +\startbuffer +\startbuffer[e] +def draw_intersection = + pair pointC, pointD ; + pointC := circleA intersectionpoint circleB ; + pointD := (reverse circleA) intersectionpoint (reverse circleB) ; + draw_dot pointC ; label.lft(btex C etex, pointC shifted (-2w,0)) ; + draw_dot pointD ; label.lft(btex D etex, pointD shifted (-2w,0)) ; +enddef ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\startbuffer[3] +start_everything ; + draw_basics ; draw_circles ; stand_out ; draw_intersection ; +stop_everything ; +\stopbuffer +\stopbuffer + +In placing the label, we must make sure that the text runs free of the lines and +curves. Again, move the \type {stand_out} macro just prior to \type +{draw_intersection} macro, so that this step is highlighted in the drawing color, +while prior steps are drawn in the default color (in this case black). + +\typebuffer \getbuffer + +\startlinecorrection[blank] +\ruledhbox{\processMPbuffer[a,b,c,d,e,3]} +\stoplinecorrection + +The line drawn through points $C$ and $D$ will be the perpendicular bisector of +the line segment connecting points $A$ and $B$. In the next step we will draw a +line using the plain \METAPOST\ \type {drawdblarrow} macro that draws arrowheads +at each end of a path. + +\startbuffer +\startbuffer[f] +def draw_bisector = + path lineCD ; + lineCD := origin -- origin shifted (2*distance,0) ; + lineCD := lineCD rotated 90 shifted 0.5[pointA,pointB] ; + lineCD := lineCD shifted (0,-distance) ; + drawdblarrow lineCD ; +enddef ; +\stopbuffer + +\startbuffer[4] +start_everything ; + draw_basics ; draw_circles ; draw_intersection ; stand_out ; + draw_bisector ; +stop_everything ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +\startlinecorrection[blank] +\ruledhbox{\processMPbuffer[a,b,c,d,e,f,4]} +\stoplinecorrection + +The following code draws the intersection of line $C-D$ and line segment $A-B$, +which can be shown to be the midpoint of segment $A-B$. + +\startbuffer +\startbuffer[g] +def draw_midpoint = + pair pointM ; + pointM := lineCD intersectionpoint lineAB ; + draw_dot pointM ; label.llft(btex M etex, pointM) ; +enddef ; +\stopbuffer + +\startbuffer[5] +start_everything ; + draw_basics ; draw_circles ; draw_intersection ; draw_bisector ; + stand_out ; draw_midpoint ; +stop_everything ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +\startlinecorrection[blank] +\ruledhbox{\processMPbuffer[a,b,c,d,e,f,g,5]} +\stoplinecorrection + +As long as we place the graphics as individual insertions in our document, +everything is fine. However, if we wish to place them all at once, or as we shall +see later, place them on top of one another in a fieldstack, it makes sense to +give them all the same bounding box. We can do this by completing the \type +{start_everything} and \type {stop_everything} commands. + +\startbuffer +\startbuffer[a] +def start_everything = + path bb ; + draw_basics ; + draw_circles ; + draw_intersection ; + draw_bisector ; + draw_midpoint ; + bb := boundingbox currentpicture ; + currentpicture := nullpicture ; +enddef ; + +def stop_everything = + setbounds currentpicture to bb ; +enddef ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +In \in {figure} [fig:1 till 5] we demonstrate the effect of this redefinition. +For this purpose we scale down the graphic to a comfortable 40\%, of course by +using an additional buffer. We also visualize the bounding box. + +\startbuffer +\startbuffer[h] +def stop_everything = + setbounds currentpicture to bb ; + draw bb withpen pencircle scaled .5pt withcolor .625yellow ; + currentpicture := currentpicture scaled .4 ; +enddef ; +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +The graphic itself is defined as follows. Watch how we use the default buffer to +keep the definitions readable. + +\startbuffer +\startbuffer +\startcombination[5*1] + {\processMPbuffer[a,b,c,h,d,e,f,g,1]} {step 1} + {\processMPbuffer[a,b,c,h,d,e,f,g,2]} {step 2} + {\processMPbuffer[a,b,c,h,d,e,f,g,3]} {step 3} + {\processMPbuffer[a,b,c,h,d,e,f,g,4]} {step 4} + {\processMPbuffer[a,b,c,h,d,e,f,g,5]} {step 5} +\stopcombination +\stopbuffer + +\placefigure + [here][fig:1 till 5] + {The five graphics, each with the same bounding box.} + {\getbuffer} +\stopbuffer + +\typebuffer \getbuffer + +As the original purpose of these graphics was not to show them side by side, but +to present them as field stack in a document to be viewed at the computer screen. +For this purpose we have to define the graphics as symbols. + +\startbuffer +\definesymbol[step 1][{\processMPbuffer[a,b,c,d,e,f,g,1]}] +\definesymbol[step 2][{\processMPbuffer[a,b,c,d,e,f,g,2]}] +\definesymbol[step 3][{\processMPbuffer[a,b,c,d,e,f,g,3]}] +\definesymbol[step 4][{\processMPbuffer[a,b,c,d,e,f,g,4]}] +\definesymbol[step 5][{\processMPbuffer[a,b,c,d,e,f,g,5]}] +\stopbuffer + +\typebuffer \getbuffer + +A field stack is a sequence of overlayed graphics. We will arrange these to cycle +manually, with clicks of the mouse, through the sequence of graphs depicting the +construction of the midpoint of segment $A-B$. So, in fact we are dealing with a +manual simulation. The definition of such a stack is as follows: + +\startbuffer +\definefieldstack + [midpoint construction] + [step 1, step 2, step 3, step 4, step 5] + [frame=on,offset=3pt,framecolor=darkyellow,rulethickness=1pt] +\stopbuffer + +\typebuffer \getbuffer + +The first argument is to be a unique identifier, the second argument takes a list +of symbols, while the third argument accepts settings. More on this command can +be found in the \CONTEXT\ manuals. + +The stack is shown as \in {figure} [fig:steps]. Its caption provides a button, +which enables the reader to cycle through the stack. We call this a stack because +the graphics are positioned on top of each other. Only one of them is visible at +any time. + +\startbuffer +\placefigure + [here][fig:steps] + {Bisecting a line segment with compass and straightedge? Just + click \goto {here} [JS(Walk_Field{midpoint construction})] to + walk through the construction! (This stack is only visible + in a \PDF\ viewer that supports widgets.)} + {\framed{\startoverlay + {\symbol[step 1]} + {\fieldstack[midpoint construction]} + \stopoverlay}} +\stopbuffer + +\typebuffer + +We cheat a bit and overlay the stack over the first symbol because otherwise +nothing shows up in print (nowadays I mostly use sumatrapdf). + +{\setupinteraction[color=darkred,contrastcolor=darkred]\getbuffer} + +At the start of this section, we mentioned three methods. When we use the first +method of putting all the graphics in an external \METAPOST\ file, the following +framework suits. We assume that the file is called \type {step.mp} and that it is +kept by the user along with his document source. We start with the definitions of +the graphic steps. These are the same as the ones shown previously. + +\starttyping +def draw_basics = ... enddef ; +def draw_circles = ... enddef ; +def draw_intersection = ... enddef ; +def draw_bisector = ... enddef ; +def draw_midpoint = ... enddef ; +def stand_out = ... enddef ; +\stoptyping + +We can safe some code by letting the \type {..._everything} take care of the +\type {beginfig} and \type {endfig} macros. + +\starttyping +def start_everything (expr n) = beginfig(n) ; ... enddef ; +def stop_everything = ... ; endfig ; enddef ; +\stoptyping + +The five graphics now become: + +\starttyping +start_everything (1) ; + stand_out ; draw_basics ; +stop_everything ; + +start_everything (2) ; + draw_basics ; stand_out ; draw_circles ; +stop_everything ; + +start_everything (3) ; + draw_basics ; draw_circles ; stand_out ; draw_intersection ; +stop_everything ; + +start_everything (4) ; + draw_basics ; draw_circles ; draw_intersection ; stand_out ; + draw_bisector ; +stop_everything ; + +start_everything (5) ; + draw_basics ; draw_circles ; draw_intersection ; draw_bisector ; + stand_out ; draw_midpoint ; +stop_everything ; +\stoptyping + +The definitions of the symbols now refer to an external +figure. + +\starttyping +\definesymbol[step 1][{\externalfigure[step.1]}] +\definesymbol[step 2][{\externalfigure[step.2]}] +\definesymbol[step 3][{\externalfigure[step.3]}] +\definesymbol[step 4][{\externalfigure[step.4]}] +\definesymbol[step 5][{\externalfigure[step.5]}] +\stoptyping + +Which method is used, depends on the way the graphics are used. In this example +we wanted to change the definition of \type {..._everything}, so here the third +method was quite useful. + +\stopsection + +\startsection[title={Simple Logos}] + +\startbuffer[ns] +numeric width, height, line, delta ; +width = 5cm ; height = width/2 ; line = height/4 ; delta = line ; + +linejoin := mitered ; pickup pencircle scaled line ; + +color nsblue ; nsblue := (0,0,1) ; +color nsyellow ; nsyellow := (1,1,0) ; + +z1 = (0, height/2) ; +z2 = (width/2-height/4, y1) ; +z3 = (width/2+height/4, y4) ; +z4 = (width, 0) ; + +z5 = (x4+height/2, y1) ; +z6 = (x4, 2y1) ; +z7 = 1.5[z5,z6] ; + +path p ; p := z1--z2--z3--z4 ; path q ; q := z3--z4--z5--z7 ; + +numeric d, lx, ly, ux, uy ; d = line/2 ; + +lx = -3d - d/3 ; ly = -d ; ux = rt x5 + d/3 ; uy = top y6 ; + +path r ; r := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle; + +lx := lx-delta ; ly := ly-delta ; ux := ux+delta ; uy := uy+delta ; + +path s ; s := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle; + +draw p withcolor nsblue ; draw q withcolor nsblue ; + +addto currentpicture also currentpicture + rotatedaround (.5[z2,z3],180) shifted (height/4,height/2) ; + +picture savedpicture ; savedpicture := currentpicture ; + +clip currentpicture to r ; +setbounds currentpicture to r ; + +savedpicture := currentpicture ; currentpicture := nullpicture ; + +fill s withcolor nsyellow ; +addto currentpicture also savedpicture ; +\stopbuffer + +Many company logos earn their beauty from their simplicity. One of the logos that +most Dutch people have imprinted in their mind is that of the Dutch Railway +Company (NS). An interesting feature of this logo is that, although it is widely +known, drawing it on a piece of paper from mind is a task that many people fail. + +\startlinecorrection[blank] +\processMPbuffer[ns] +\stoplinecorrection + +This logo makes a good candidate for demonstrating a few fine points of drawing +graphics, like using linear equations, setting line drawing characteristics, +clipping and manipulating bounding boxes. + +The implementation below is quite certainly not according to the official +specifications, but it can nevertheless serve as an example of defining such +logos. + +\startbuffer[a] +numeric width ; width = 3cm ; +numeric height ; height = width/2 ; +numeric line ; line = height/4 ; +\stopbuffer + +As always, we need to determine the dimensions first. Here, both the height and +line width depend on the width of the graphic. + +Instead of calculating the blue shape such that it will be a filled outline, we +will draw the logo shape using line segments. This is why we need the \type +{line} parameter. + +\typebuffer[a] + +We want sharp corners which can be achieved by setting \type {linejoin} to \type +{mitered}. + +\startbuffer[b] +linejoin := mitered ; pickup pencircle scaled line ; +\stopbuffer + +\typebuffer[b] + +The colors are rather primary blue and yellow. At the time of writing this +manual, Dutch trains are still painted yellow, so we will use that shade as +background color. + +\startbuffer[c] +color nsblue ; nsblue := (0,0,1) ; +color nsyellow ; nsyellow := (1,1,0) ; +\stopbuffer + +\typebuffer[c] + +We will now describe the main curves. Although these expressions are not that +advanced, they demonstrate that we can express relationships instead of using +assignments. + +\startbuffer[d] +z1 = (0, height/2) ; +z2 = (width/2-height/4, y1) ; +z3 = (width/2+height/4, y4) ; +z4 = (width, 0) ; + +path p ; p := z1--z2--z3--z4 ; +\stopbuffer + +\typebuffer[d] + +Although it is accepted to consider \type {z} to be a variable, it is in fact a +\type {vardef} macro, that expands into a pair \type {(x,y)}. This means that the +previous definitions internally become: + +\starttyping +(x1,y1) = (0, height/2) ; +(x2,y2) = (width/2-height/4, y1) ; +(x3,y3) = (width/2+height/4, y4) ; +(x4,y4) = (width, 0) ; +\stoptyping + +These 8 relations can be solved by \METAPOST, since all dependencies are known. + +\starttyping +x1 = 0 ; y1 = height/2 ; +x2 = width/2-height/4 ; y2 = y1 ; +x3 = width/2+height/4 ; y3 = y4 ; +x4 = width ; y4 = 0 ; +\stoptyping + +Since we express the variables \type {x} and \type {y} in terms of relations, we +cannot reuse them, because that would mean that inconsistent relations occur. So, +the following lines will lead to an error message: + +\starttyping +z1 = (10,20) ; z1 = (30,50) ; +\stoptyping + +For similar reasons, we may not assign a value (using \type {:=}) to such a \type +{z} variable. Within a \METAPOST\ figure, \type {z} variables are automatically +saved, which means that they can be reused for each figure. + +\startbuffer[x] +drawpath p ; drawpoints p ; drawpointlabels p ; +\stopbuffer + +So far, we have defined the following segment of the logo. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,x] +\stoplinecorrection + +\startbuffer[e] +z5 = (x4+height/2, y1) ; +z6 = (x4, 2y1) ; +z7 = 1.5[z5,z6] ; + +path q ; q := z3--z4--z5--z7 ; +\stopbuffer + +The next expressions are used to define the second segment. The third expression +determines \type {z7} to be positioned on the line \type {z5--z6}, where we +extend this line by 50\%. + +\typebuffer[e] + +\startbuffer[x] +drawpath q ; drawpoints q ; drawpointlabels q ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,x] +\stoplinecorrection + +If we combine these two segments, we get: + +\startbuffer[x] +drawpath p ; drawpoints p ; drawpointlabels p ; +swappointlabels := true ; +drawpath q ; drawpoints q ; drawpointlabels q ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,x] +\stoplinecorrection + +However, when we draw them using the right linewidth and color, you will notice +that we're not yet done: + +\startbuffer[f] +draw p withcolor nsblue ; draw q withcolor nsblue ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f] +\stoplinecorrection + +The second curve is similar to the first one, but rotated over 180 degrees. + +\startbuffer[g] +addto currentpicture also currentpicture + rotatedaround (.5[z2,z3],180) shifted (height/4,height/2) ; +\stopbuffer + +\typebuffer[g] + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f,g] +\stoplinecorrection + +In order to get the sharp edges, we need to clip off part of +the curves and at first sight, we may consider using a +scaled bounding box. However, when we show the natural +bounding box, you will notice that a more complicated bit of +calculations is needed. + +\startbuffer[x] +draw boundingbox currentpicture + withpen pencircle scaled .5mm withcolor .625white ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f,g,x] +\stoplinecorrection + +The right clip path is calculated using the following expressions. Watch how we +use \type {rt} and \type {top} to correct for the linewidth. + +\startbuffer[h] +numeric d, lx, ly, ux, uy ; d = line/2 ; + +lx = -3d - d/3 ; ly = -d ; ux = rt x5 + d/3 ; uy = top y6 ; + +path r ; r := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle; +\stopbuffer + +\typebuffer[h] + +The clipping path is applied by saying: + +\startbuffer[i] +clip currentpicture to r ; +\stopbuffer + +\typebuffer[i] + +The result is quite acceptable: + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f,g,h,i] +\stoplinecorrection + +But, if you watch closely to how this graphic extends into to left margin of this +document, you will see that the bounding box is not yet right. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f,g,h,i,x] +\stoplinecorrection + +\startbuffer[j] +setbounds currentpicture to r ; +\stopbuffer + +\typebuffer[j] + +We use the same path \type {r} to correct the bounding box. + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f,g,h,i,j,x] +\stoplinecorrection + +There are a few subtle points involved, like setting the \type {linejoin} +variable. If we had not set it to \type {mitered}, we would have got round +corners. We don't set the \type {linecap}, because a flat cap would not extend +far enough into the touching curve and would have left a small hole. The next +example shows what happens if we set these variables to the wrong values: + +\startbuffer[bb] +linejoin := rounded ; linecap := mitered ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,bb,c,d,e,f,g,h,i,j] +\stoplinecorrection + +In fact we misuse the fact that both curves overlay each other. + +\startbuffer[f] +draw p withcolor nsblue ; draw q withcolor .625white ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b,c,d,e,f,g,h,i,j] +\stoplinecorrection + +The complete logo definition is a bit more extensive because we also want to add +a background. Because we need to clip the blue foreground graphic, we must +temporarily store it when we fill the background. + +\typebuffer[ns] + +For practical use it makes sense to package this definition in a macro to which +we pass the dimensions. + +\stopsection + +\startsection[title={Music sheets}] + +The next example demonstrates quite some features. Imagine that we want to make +us a couple of sheets so that we can write a musical masterpiece. Let's also +forget that \TEX\ can draw lines, which means that somehow we need to use +\METAPOST. + +Drawing a bar is not that complicated as the following code demonstrates. + +\startbuffer +\startusableMPgraphic{bar} + vardef MusicBar (expr width, gap, linewidth, barwidth) = + image + ( interim linecap := butt ; + for i=1 upto 5 : + draw ((0,0)--(width,0)) shifted (0,(i-1)*gap) + withpen pencircle scaled linewidth ; + endfor ; + for i=llcorner currentpicture -- ulcorner currentpicture , + lrcorner currentpicture -- urcorner currentpicture : + draw i withpen pencircle scaled barwidth ; + endfor ; ) + enddef ; +\stopusableMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +We can define the sidebars a bit more efficient using two predefined subpaths: + +\starttyping +for i=leftboundary currentpicture, rightboundary currentpicture : +\stoptyping + +We define a macro \type {MusicBar} that takes four arguments. The first two +determine the dimensions, the last two concern the line widths. Now watch how we +can use this macro: + +\startbuffer +\includeMPgraphic{bar} ; +draw MusicBar (200pt, 6pt, 1pt, 2pt) ; +draw MusicBar (300pt, 6pt, 1pt, 2pt) shifted (0,-30pt) ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +As you can see in this example, the bar is a picture that can be transformed +(shifted in our case). However, a close look at the macro teaches us that it does +a couple of draws too. This is possible because we wrap the whole in an image +using the \type {image} macro. This macro temporary saves the current picture, +and at the end puts the old \type {currentpicture} under the new one. + +We wrap the whole in a \type {vardef}. This means that the image is returned as +if it was a variable. Actually, the last thing in a \type {vardef} should be a +proper return value, in our case a picture. This also means that we may not end +the \type {vardef} with a semi colon. So, when the content of the \type {vardef} +is expanded, we get something + +\starttyping +draw some_picture ... ; +\stoptyping + +Because we are still drawing something, we can add transform directives and set +attributes, like the color. + +The second \type {for} loop demonstrates two nice features. Instead of repeating +the draw operation by copying code, we apply it to a list, in our case a list of +paths. This list contains two simple line paths. Because an \type {image} starts +with a fresh \type {currentpicture}, we can safely use the bounding box data to +determine the height of the line. + +The next step in producing the sheets of paper is to put several bars on a page, +preferable with the width of the current text. This time we will use a reusable +graphic, because each bar is the same. + +\startbuffer +\startreusableMPgraphic{bars} + \includeMPgraphic{bar} ; + draw MusicBar (TextWidth, 6pt, 1pt, 2pt) withcolor .625yellow ; +\stopreusableMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +\startlinecorrection[blank] +\reuseMPgraphic{bars} +\stoplinecorrection + +Instead of going through the trouble of letting \METAPOST\ calculate the positions +of the bars, we will use \TEX. We put 12 bars on a page and let \TEX\ take care +of the inter||bar spacing. Because we only want stretchable space between bars, +called glue in \TEX, we need to remove the last added glue. + +\startnotmode[screen] + +\startbuffer[music] +\startstandardmakeup[doublesided=no,page=] + \dorecurse{15}{\reuseMPgraphic{bars}\vfill}\removelastskip +\stopstandardmakeup +\stopbuffer + +\stopnotmode + +\startmode[screen] + +\startbuffer[music] +\startstandardmakeup[doublesided=no,page=] + \dorecurse{10}{\reuseMPgraphic{bars}\vfill}\removelastskip +\stopstandardmakeup +\stopbuffer + +\stopmode + +\typebuffer[music] + +\startusableMPgraphic{bar} + vardef MusicBar (expr width, gap, linewidth, barwidth) = + image + ( interim linecap := butt ; + for i=1 upto 5 : + draw ((0,0)--(width,0)) + randomized (1pt,1.5pt) + shifted (0,(i-1)*gap) + withpen pencircle scaled linewidth ; + endfor ; + for i=llcorner currentpicture -- ulcorner currentpicture , + lrcorner currentpicture -- urcorner currentpicture : + draw i randomized 2pt shifted (0,-1pt) + withpen pencircle scaled barwidth ; + endfor ; ) + enddef ; +\stopusableMPgraphic + +\startreusableMPgraphic{bars} % trigger a new one + \includeMPgraphic{bar} ; + draw MusicBar (TextWidth, 6pt, 1pt, 2pt) withcolor .625yellow ; +\stopreusableMPgraphic + +It may add to the atmosphere of handy||work if you slightly randomize the lines. +We leave it up to the reader to figure out how the code should be changed to +accomplish this. + +\startlinecorrection[blank] +\reuseMPgraphic{bars} +\stoplinecorrection + +The complete result is shown on the next page. + +\startpostponing +\getbuffer[music] +\stoppostponing + +\stopsection + +\startsection[title={The euro symbol}] + +When Patrick Gundlach posted a nice \METAPOST\ version of the euro symbol to the +\CONTEXT\ discussion list, he added the comment \quotation {The official +construction is ambiguous: how thick are the horizontal bars? How much do they +stick out to the left? Is this thing a circle or what? Are the angles on the left +side of the bars the same as the one on the right side? \unknown} The alternative +below is probably not as official as his, but permits a finetuning. You are +warned: whatever you try, the euro {\em is} and {\em will remain} an ugly symbol. + +We use a couple of global variables to control the euro shape within reasonable +bounds. Then we define two circles. Next we define a vertical line that we use in +a couple of cut and paste operations. Watch how the top left point of the outer +circle determines the slant of the line that we use to slice the vertical bars. + +\startbuffer[euro] +boolean trace_euro ; trace_euro := false ; + +vardef euro_symbol = image ( % begin_of_euro + +if unknown euro_radius : euro_radius := 2cm ; fi ; +if unknown euro_width : euro_width := 3euro_radius/16 ; fi ; +if unknown euro_r_offset : euro_r_offset := euro_width ; fi ; +if unknown euro_l_offset : euro_l_offset := euro_radius/32 ; fi ; +if unknown euro_l_shift : euro_l_shift := euro_r_offset ; fi ; +if unknown euro_v_delta : euro_v_delta := euro_width/4 ; fi ; + +save + outer_circle, inner_circle, hor_bar, + right_line, right_slant, top_slant, bot_slant, + euro_circle, euro_topbar, euro_botbar ; + +path + outer_circle, inner_circle, hor_bar, + right_line, right_slant, top_slant, bot_slant, + euro_circle, euro_topbar, euro_botbar ; + +outer_circle := fullcircle scaled euro_radius ; +inner_circle := fullcircle scaled (euro_radius-euro_width) ; + +if trace_euro : for i = outer_circle, inner_circle : + draw i withpen pencircle scaled 1pt withcolor .5white ; +endfor ; fi ; + +right_line := + (lrcorner outer_circle -- urcorner outer_circle) + shifted (-euro_r_offset,0) ; + +outer_circle := outer_circle cutbefore right_line ; + +right_slant := + point 0 of outer_circle + -- origin shifted (0,ypart lrcorner outer_circle) ; + +euro_circle := buildcycle(outer_circle, right_line, + reverse inner_circle, reverse right_slant) ; + +hor_bar := (-euro_radius,0) -- (euro_radius,0) ; + +top_slant := + right_slant shifted (-euro_radius+euro_r_offset-euro_l_offset,0) ; + +bot_slant := + top_slant shifted (0,-euro_l_shift) ; + +if trace_euro : for i = right_line, right_slant, top_slant, bot_slant : + draw i withpen pencircle scaled 1pt withcolor .5white ; +endfor ; fi ; + +euro_topbar := buildcycle + (top_slant, hor_bar shifted (0, euro_v_delta), + right_slant, hor_bar shifted (0, euro_v_delta+euro_width/2)) ; + +euro_botbar := buildcycle + (bot_slant, hor_bar shifted (0,-euro_v_delta), + right_slant, hor_bar shifted (0,-euro_v_delta-euro_width/2)) ; + +for i = euro_circle, euro_topbar, euro_botbar : + draw i withpen pencircle scaled 0 ; +endfor ; +for i = euro_circle, euro_topbar, euro_botbar : + fill i withpen pencircle scaled 0 ; +endfor ; + +if trace_euro : + drawpoints euro_circle withcolor red ; + drawpoints euro_topbar withcolor green ; + drawpoints euro_botbar withcolor blue ; +fi ; + +) enddef ; % end_of_euro +\stopbuffer + +\typebuffer[euro] + +We only set a parameter when it is not yet set. This has +the advantage that we don't have to set them when we change +one. This way of manipulating paths (cutting and building) +does not always work well because of rounding errors, but +here it does work. + +\startbuffer[demo] +euro_radius := 4cm ; trace_euro := true ; draw euro_symbol ; +\stopbuffer + +\typebuffer[demo] + +For educational purposes, we have added a bit of +tracing. When enabled, the euro shows up as: + +\startlinecorrection[blank] +\processMPbuffer[euro,demo] +\stoplinecorrection + +Of course it would be best to define the euro as one shape, but we won't go +though that process right now. By packaging the combined paths in an image, we +can conveniently color the euro symbol: + +\startbuffer[demo] +draw euro_symbol withcolor .625red ; +\stopbuffer + +\typebuffer[demo] + +\startlinecorrection[blank] +\processMPbuffer[euro,demo] +\stoplinecorrection + +You may wonder why we both draw and fill the euro, using a pen with zero width. +We've done this in order to demonstrate the \type {redraw} and \type {refill} +macros. + +\startbuffer[extra] +redraw currentpicture withpen pencircle scaled 4pt withcolor .625yellow ; +refill currentpicture withcolor .625white ; +setbounds currentpicture to boundingbox currentpicture enlarged 2pt ; +\stopbuffer + +\typebuffer[extra] + +\startlinecorrection[blank] +\processMPbuffer[euro,demo,extra] +\stoplinecorrection + +\stopsection + +\startsection[title={Killing time}] + +Not seldom \TEX\ users want to use this program and its meta||relatives as +general purpose tools, even at the cost of quite some effort or suboptimal +results. Imagine that you are under way from our planet to Mars. After a long +period of sleep you wake up and start wondering on what track you are. You even +start questioning the experts that send you on your way, so you pop open your +laptop, launch your editor and start metaposting. + +First you need to determine the begin and end points of your journey. For now it +is enough to know the relative angle of the paths that both planets follow as +well as the path themselves. We assume circular paths. + +\startbuffer +path a ; a := fullcircle scaled 3cm ; +path b ; b := fullcircle scaled 2cm rotated 120 ; + +draw a withpen pencircle scaled 1mm withcolor .625red ; +draw b withpen pencircle scaled 1mm withcolor .625yellow ; + +draw point 0 of a withpen pencircle scaled 2mm ; +draw point 0 of b withpen pencircle scaled 2mm ; +\stopbuffer + +\typebuffer + +The rotation 120 can be calculated from the relative starting points and time the +journey will take. Alternatively we can use the time along the path, but this +would be a bit more fuzzy later on. \footnote {In case you wonder why \METAPOST\ +talks about the time on a path, you now have a cue.} + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +After a bit of playing with drawing paths between the two points, you decide to +make a macro. We want to feed the angle between the paths but also the connecting +path. So, we have to pass a path, but unfortunately we don't have direct access +to the points. By splitting the argument definition we can pass an expression +first, and a wildcard argument next. + +\startbuffer +\startuseMPgraphic{gamble} +def Gamble (expr rot) (text track) = + path a ; a := fullcircle scaled 3cm ; + path b ; b := fullcircle scaled 2cm rotated rot ; + + pair aa ; aa := point 0 of a ; + pair bb ; bb := point 0 of b ; + path ab ; ab := track ; + + draw a withpen pencircle scaled 1mm withcolor .625red ; + draw b withpen pencircle scaled 1mm withcolor .625yellow ; + + draw aa withpen pencircle scaled 2mm ; + draw bb withpen pencircle scaled 2mm ; + + drawarrow ab withpen pencircle scaled 1mm withcolor .625white ; + + setbounds currentpicture to boundingbox a enlarged 2mm ; + draw boundingbox currentpicture withpen pencircle scaled .25mm ; +enddef ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +Because at this distance nobody will bother us with the thickness of the pen and +colors, we code them the hard way. We create our own universe by setting a fixed +boundingbox. + +We leave the Earth in the most popular way, straight upwards and after a few +cycles, we leave it parallel to the surface. The path drawn reminds much of the +trajectories shown in popular magazines. + +\startbuffer +\startMPcode +\includeMPgraphic{gamble} ; +Gamble(120, aa {(0,1)} .. bb) ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +According to \METAPOST, when we leave the Earth straight upwards and want a +smooth trajectory, we have to pass through outer space. + +\startbuffer +\startMPcode +\includeMPgraphic{gamble} ; +Gamble(120,aa {(1,0)} .. bb) ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +Given that we want a smooth path as well as a short journey, we can best follow +Mars' path. Here we face the risk that when we travel slower than Mars does, we +have a problem. + +\startbuffer +\startMPcode +\includeMPgraphic{gamble} ; +Gamble(120,aa {dir 90} .. {precontrol 0 of b rotated 90} bb) ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +We can even travel a shorter path when we leave Earth at the surface that faces +the point of arrival. + +\startbuffer +\startMPcode +\includeMPgraphic{gamble} ; +Gamble(120,aa .. {precontrol 0 of b rotated 90} bb) ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +In the end we decide that although the trajectories look impressive, we will not +trust our lives to \METAPOST. A beautiful path is not neccessarily a good path. +But even then, this macro provides a nice way to experiment with directions, +controls and tensions. + +\stopsection + +% \startsection[title={Animations}] +% +% {\em Although \METAPOST\ is not that well suited for free hand drawings, you can +% use it to make stylistics animations.} +% +% \stopsection + +\startsection[title={Selective randomization}] + +In this document we have used a lot of randomization. Because \CONTEXT\ often +needs multiple runs to sort out cross references, positions, tables of contents, +and so on, being real random every run would result in endless runs to get things +right, because the size of graphics changes. This is prevented by storing the +random seed betweeen runs. You can remove the \type {tuc} file to get a new seed +(or run \type {context --purgeall}). + +Here is another example of randomization. This time we only randomize the control +points so the main shape sort of remains intact which can be handy when you use +such random shapes around text but still want a predictable size. + +\startbuffer +\startMPcode +fill fullcircle scaled 2cm + randomizedcontrols 0.1cm + withcolor darkred + withtransparency (1,.5) ; +fill ((1cm,0)--(0,1cm)--(-1cm,0)--cycle) + randomizedcontrols 0.1cm + withcolor darkblue + withtransparency (1,.5) ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +\startbuffer +\startMPcode +draw image ( + fill fullcircle scaled 2cm + withcolor darkred + withtransparency (1,.5) ; + fill ((1cm,0)--(0,1cm)--(-1cm,0)--cycle) + withcolor darkblue + withtransparency (1,.5) ; +) randomizedcontrols 0.1cm ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +\stopsection + +\startsection[title=Snapping] + +There are quite some helpers in \METAFUN\ and I must admit that I forgot +about most. Some just ended up in the core because they can be useful, others +serve as illustration. Here's one of them: \type {snapped}. First we define +a few helpers that we then use to check out a few shapes. + +\startbuffer +\startMPdefinitions +def ShowSnapGrid(text shape) = + fill (shape xsized 77mm) withcolor white/3 ; + draw image ( + for i=10mm step 5mm until 100mm : + draw fullsquare scaled i ; + endfor ; + ) withcolor 2white/3 ; + drawpoints (shape xsized 77mm) withcolor black ; +enddef ; + +vardef SnapShape expr shape = + image ( + draw shape ; + drawpoints shape ; + ) +enddef ; + +vardef ShowSnapShape expr shape = + ShowSnapGrid(shape); + + draw SnapShape(shape xsized 77mm snapped -5mm ) withcolor red ; + draw SnapShape(shape xsized 77mm snapped 5mm ) withcolor red ; + draw SnapShape(shape xsized 77mm snapped (5mm,10mm)) withcolor green ; + draw SnapShape(shape xsized 77mm snapped (5mm,15mm)) withcolor blue ; + draw SnapShape(shape xsized 77mm snapped (5mm,20mm)) withcolor yellow ; +enddef ; +\stopMPdefinitions +\stopbuffer + +\typebuffer \getbuffer + +In \in {figures} [fig:snapper:1], \in [fig:snapper:2] and \in [fig:snapper:3] we +see how the original shape gets snapped on the grid. Of course in more complex +images the direction of the snapping can change the result in an unwanted way, +like overlapping shapes that obscure others, but normally this snapping is only +useful for simple predictable cases (like title pages). + +\startplacefigure[reference=fig:snapper:1,title={Messing with \type{fullcircle}.}] +\startMPcode + ShowSnapShape(fullcircle); +\stopMPcode +\stopplacefigure + +\startplacefigure[reference=fig:snapper:2,title={\type{fullsquare}}] +\startMPcode + ShowSnapShape(fullsquare); +\stopMPcode +\stopplacefigure + +\startplacefigure[reference=fig:snapper:3,title={\type{fulltriangle}}] +\startMPcode + ShowSnapShape(fulltriangle); +\stopMPcode +\stopplacefigure + +\stopsection + +\startsection[title=Arrowheads] + +Arrows are actually drawn quite well in \METAPOST, as the arrowheads nicely adapt +to the direction of the point where the arrowhead is attached. There are however +some limitations as the following examples demonstrate: arrows don't work well +with transparency and you can probably figure out why. Alan Braslau came up with +an extension that allows to set the dimple of the head. You can see all this +in \in {figure} [fig:arrowheads]. + +\startbuffer[a] +numeric unit ; unit := mm ; + +drawoptions(withcolor .6blue withtransparency (1,.25)) ; + +pickup pencircle scaled 2unit ; ahlength := 6unit ; + +picture p ; p := image ( + drawarrow reverse fullcircle rotated - 5 scaled 50unit ; + drawarrow reverse fullcircle rotated -10 scaled 30unit ; +) shifted ( -45unit, 0unit) ; + +for i=0 step 90 until 360 : draw p rotated i ; endfor ; + +currentpicture := currentpicture shifted - center currentpicture ; + +p := currentpicture ; p := image ( + draw llcorner p -- center p ; + drawarrow llcorner p -- 0.875[llcorner p,center p] ; +) ; + +for i=0 step 90 until 360 : draw p rotated i ; endfor ; + +clip currentpicture to boundingbox (fullcircle scaled 80unit) ; + +if lua.mp.mode("screen") : + currentpicture := currentpicture ysized .4TextHeight ; +else : + currentpicture := currentpicture xsized .4TextWidth ; +fi ; +\stopbuffer + +\typebuffer[a] + +\startbuffer[b] + resetarrows ; +\stopbuffer + +\startbuffer[a1] + ahvariant := 1 ; +\stopbuffer +\startbuffer[a2] + ahvariant := 2 ; +\stopbuffer + +\startbuffer[a3] + ahvariant := 1 ; ahdimple := 1/2 ; +\stopbuffer +\startbuffer[a4] + ahvariant := 1 ; ahdimple := 1 ; +\stopbuffer +\startbuffer[a5] + ahvariant := 1 ; ahdimple := 5/2 ; +\stopbuffer + +\startplacefigure[reference=fig:arrowheads,title=The way arrowheads are constructed.] + \doifelsemode {screen} { + \setupcombination[nx=3,ny=2] + } { + \setupcombination[nx=2,ny=3] + } + \startcombination[distance=2em] + {\processMPbuffer[a, b]} {\tttf ahvariant=0} + {\processMPbuffer[a1,a,b]} {\tttf ahvariant=1} + {\processMPbuffer[a2,a,b]} {\tttf ahvariant=2} + {\processMPbuffer[a3,a,b]} {\tttf ahvariant=1, ahdimple=1/2} + {\processMPbuffer[a4,a,b]} {\tttf ahvariant=1, ahdimple=1} + {\processMPbuffer[a5,a,b]} {\tttf ahvariant=1, ahdimple=5/2} + \stopcombination +\stopplacefigure + +\stopsection + +\startsection[title=Teaser] + +Sometimes, when playing with \METAPOST\ you run into interesting cases. Here is +one. The result is shown in \in {figure} [fig:teaser:1]. + +\startbuffer +\startusableMPgraphic{BackgroundTeaser} + fill OverlayBox enlarged 1mm withcolor darkyellow ; % bleed + path p ; p := OverlayBox enlarged -5mm ; + path q ; q := OverlayBox enlarged -10mm ; + fill q withcolor white ; + drawoptions(withcolor darkred) ; + fill reverse topboundary q -- topboundary p -- cycle ; + fill reverse bottomboundary q -- bottomboundary p -- cycle ; + drawoptions(withcolor darkgreen) ; + fill reverse leftboundary q -- leftboundary p -- cycle ; + fill reverse rightboundary q -- rightboundary p -- cycle ; +\stopusableMPgraphic + +\defineoverlay + [BackgroundTeaser] + [\useMPgraphic{BackgroundTeaser}] + +\framed + [frame=off, + offset=15mm, + background=BackgroundTeaser, + align=normal] + {\input knuth } +\stopbuffer + +\typebuffer + +\startplacefigure[reference=fig:teaser:1,title=Can you guess what happens here?] + \getbuffer +\stopplacefigure + +\stopsection + +\startsection[title={Lists}] + +For some specific purpose I needed to sort a list of paths and therefore +\METAFUN\ comes with a quick sort macro. Its working can be demonstrated by an +example. + +\startbuffer[a] +pair p[], pp[] ; numeric n ; n := 25 ; +for i=1 upto n : p[i] := origin randomized 4cm ; endfor ; +\stopbuffer + +\startbuffer[b] +copylist(p,pp) ; % unsorted +drawarrow listtolines(pp) shifted ( 0,0) withcolor darkblue ; +\stopbuffer + +\startbuffer[c] +copylist(p,pp) ; sortlist(pp)() ; % sorted +drawarrow listtolines(pp) shifted (300,0) withcolor darkyellow ; +\stopbuffer + +\startbuffer[d] +copylist(p,pp) ; sortlist(pp)(xpart) ; +drawarrow listtolines(pp) shifted (100,0) withcolor darkred ; + +\stopbuffer +\startbuffer[e] +copylist(p,pp) ; sortlist(pp)(ypart) ; +drawarrow listtolines(pp) shifted (200,0) withcolor darkgreen ; +\stopbuffer + +\startbuffer[f] +vardef whow expr p = (xpart p + ypart p) enddef ; + +copylist(p,pp) ; sortlist(pp)(whow) ; +drawarrow listtolines(pp) shifted (400,0) withcolor darkcyan ; +\stopbuffer + +\startbuffer[g] +vardef whow expr p = (xpart p ++ ypart p) enddef ; + +copylist(p,pp) ; sortlist(pp)(whow) ; +drawarrow listtolines(pp) shifted (500,0) withcolor darkmagenta ; +\stopbuffer + +\typebuffer[a,b,c,d,e,f,g] + +The result of this code is shown in \in {figure} [fig:sorting]. + +\startplacefigure[reference=fig:sorting,title={Using the sorter.}] + \startcombination[3*2] + {\processMPbuffer[a,b]} {\tttf unsorted} + {\processMPbuffer[a,c]} {\tttf sorted} + {\processMPbuffer[a,d]} {\tttf xpart} + {\processMPbuffer[a,e]} {\tttf ypath} + {\processMPbuffer[a,f]} {\tttf xpart p + ypart p} + {\processMPbuffer[a,g]} {\tttf xpart p ++ ypart p} + \stopcombination +\stopplacefigure + +There is a helper that converts a list of paths into a shape that covers all +of them. In \in {figure} [fig:shapedlist] three shaped lists are shown. + +\startbuffer[a] + def ShowShape(expr e) = + draw image ( + + save p ; path p[] ; + + def MakeShape(expr i,w,h,x,y) = + p[i] := e + xysized ((w,h) randomized (2mm,1mm)) + shifted ((x,y) randomized (2mm,1mm)) ; + enddef ; + + MakeShape(1,40mm,6mm,10mm, 0mm) ; + MakeShape(2,50mm,5mm, 5mm,-10mm) ; + MakeShape(3,20mm,8mm,30mm,-20mm) ; + MakeShape(4,55mm,5mm,10mm,-30mm) ; + MakeShape(5,55mm,5mm, 5mm,-50mm) ; + + save s ; path s ; s := shapedlist(p) ; drawarrow s ; + + linejoin := butt ; + + for i=1 upto 5 : + fill p[i] withcolor .75white withtransparency (1,.5) ; + draw thetextext("\tttf " & decimal i, center p[i]) ; + endfor ; + + ) ysized 4cm ; + enddef ; +\stopbuffer + +\typebuffer[a] + +\startbuffer[b] +ShowShape(unitsquare) +\stopbuffer + +\startbuffer[c] +ShowShape(unitcircle) +\stopbuffer + +\startbuffer[d] +ShowShape(unittriangle) +\stopbuffer + +\startplacefigure[reference=fig:shapedlist,title={The \type {shapedlist} macro returns the envelope that covers all the paths in the list.}] + \startcombination[3*1] + {\processMPbuffer[a,b]} {\tttf unitsquare} + {\processMPbuffer[a,c]} {\tttf unitcircle} + {\processMPbuffer[a,d]} {\tttf unittriangle} + \stopcombination +\stopplacefigure + +\stopsection + +\startsection[title=Table cells] + +Sometimes a standard \CONTEXT\ feature doesn't work out as expected. Take the +following table: + +\startbuffer +\bTABLE[frame=on,framecolor=blue,rulethickness=1pt] + \bTR + \bTD test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD[framecolor=magenta] test \eTD + \bTD test \eTD + \bTD test \eTD + \eTR + \bTR + \bTD test \eTD + \bTD[framecolor=red] test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD[framecolor=green] test \eTD + \eTR +\eTABLE +\stopbuffer + +\typebuffer + +Because cells are drawn top|-|down and left|-|right a next cell border +overruns the previous one. + +\startlinecorrection +\getbuffer +\stoplinecorrection + +\startbuffer +\bTABLE[frame=on,framecolor=blue,rulethickness=1pt] + \bTR + \bTD test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD[framecolor=magenta,frameoffset=-.5pt] test \eTD + \bTD test \eTD + \bTD test \eTD + \eTR + \bTR + \bTD test \eTD + \bTD[framecolor=red,frameoffset=-.5pt] test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD[framecolor=green,frameoffset=-.5pt] test \eTD + \eTR +\eTABLE +\stopbuffer + +You can try this: + +\typebuffer + +which gives us something that is not okay either for cells that touch an edge: + +\startlinecorrection +\getbuffer +\stoplinecorrection + +but we can cheat: + +\startlinecorrection +\framed + [offset=overlay, + frameoffset=.5pt, + framecolor=blue, + rulethickness=1pt] + {\getbuffer} +\stoplinecorrection + +This is achieved by framing the whole table: + +\starttyping +\framed + [offset=overlay, + frameoffset=.5pt, + framecolor=blue, + rulethickness=1pt] + {...} +\stoptyping + +\startbuffer +\startuseMPgraphic{cell:innerframe}{innercolor} + draw OverlayBox enlarged -1.5OverlayLineWidth + withpen pensquare scaled OverlayLineWidth + withcolor \MPvar{innercolor} ; +\stopuseMPgraphic + +\defineoverlay + [innerframe] + [{\uniqueMPgraphic{cell:innerframe}% + {innercolor=\framedparameter{innercolor}}}] + +\bTABLE[frame=on,framecolor=blue,rulethickness=1pt,innercolor=magenta] + \bTR + \bTD test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD[background=innerframe] test \eTD + \bTD test \eTD + \bTD test \eTD + \eTR + \bTR + \bTD test \eTD + \bTD[background=innerframe,innercolor=red] test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD test \eTD + \bTD[background=innerframe,innercolor=green] test \eTD + \eTR +\eTABLE +\stopbuffer + +A \METAPOST\ alternative is also possible and it gives a bit nicer +interface too: + +\typebuffer + +We get: + +\startlinecorrection +\getbuffer +\stoplinecorrection + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-functions.tex b/doc/context/sources/general/manuals/metafun/metafun-functions.tex new file mode 100644 index 000000000..780127408 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-functions.tex @@ -0,0 +1,611 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-functions + +\environment metafun-environment + +\startchapter[title={Functions}] + +\index{functions} + +\startintro + +\METAPOST\ provides a wide range of functions, like \type {sind} and \type +{floor}. We will discuss most of them here and define a few more. We will also +introduce a few methods for drawing grids and functions. + +\stopintro + +\startsection[title={Overview}] + +What follows is a short overview of the functions that can be applied to numeric +expressions and strings. Functions that operate on pairs, colors, paths and +pictures are discussed in other chapters. + +First of all we have \type {+}, \type {-}, \type {/} and \type {*}. For as far as +is reasonable, you can apply these to numerics, pairs and colors. Strings can be +concatenated by \type {&}. + +Pythagorean addition is accomplished by \type {++}, while Pythagorean subtraction +is handled by \type {+-+}. The \type {**} operator gives you exponentiation. The +nature of the \METAPOST\ language is such that you can easily define interesting +functions using such symbols. + +The logarithmic functions are based on bytes. This makes them quite accurate but +forces you to think like a computer. + +\starttabulate[|lT|l|] +\HL +\NC mexp(x) \NC expential function with base 256 \NC \NR +\NC mlog(x) \NC logarithm with base 256 \NC \NR +\HL +\stoptabulate + +The basic goniometric functions operate on degrees, which is why they have a +\quote {d} in their name. + +\starttabulate[|lT|l|] +\HL +\NC cosd(x) \NC cosine of $x$ with $x$ in degrees \NC \NR +\NC sind(x) \NC sine of $x$ with $x$ in degrees \NC \NR +\HL +\stoptabulate + +There are three ways to truncate numbers. The \type {round} function can also +handle pairs and colors. + +\starttabulate[|lT|l|] +\HL +\NC ceiling(x) \NC the least integer greater than or equal to $x$ \NC \NR +\NC floor(x) \NC the greatest integer less than or equal to $x$ \NC \NR +\NC round(x) \NC round each component of $x$ to the nearest integer \NC \NR +\HL +\stoptabulate + +Of course we have: + +\starttabulate[|lT|l|] +\HL +\NC x mod y \NC the remainder of $x/y$ \NC \NR +\NC x div y \NC the integer part of $x/y$ \NC \NR +\NC abs(x) \NC the absolute value of $x$ \NC \NR +\NC sqrt(x) \NC the square root of $x$ \NC \NR +\NC x dotprod y \NC the dot product of two vectors \NC \NR +\HL +\stoptabulate + +What would life be without a certain randomness and uncertainty: + +\starttabulate[|lT|l|] +\HL +\NC normaldeviate \NC a number with mean 0 and standard deviation 1 \NC \NR +\NC uniformdeviate(x) \NC a number between zero and $x$ \NC \NR +\HL +\stoptabulate + +The following functions are actually macros: + +\starttabulate[|lT|l|] +\HL +\NC decr(x,n) \NC decrement $x$ by $n$ \NC \NR +\NC incr(x,n) \NC increment $x$ by $n$ \NC \NR +\NC max(a,b,..) \NC return the maximum value in the list \NC \NR +\NC min(a,b,..) \NC return the minimum value in the list \NC \NR +\HL +\stoptabulate + +The \type {min} and \type {max} funtions can be applied to numerics as well as +strings. + +The following functions are related to strings: + +\starttabulate[|lT|l|] +\HL +\NC oct s \NC string representation of an octal number \NC \NR +\NC hex s \NC string representation of a hexadecimal number \NC \NR +\NC str s \NC string representation for a suffix \NC \NR +\NC ASCII s \NC \ASCII\ value of the first character \NC \NR +\NC char x \NC character of the given \ASCII\ code \NC \NR +\NC decimal x \NC decimal representation of a numeric \NC \NR +\HL +\stoptabulate + +With \type {substring (i,j) of s} you can filter the substring bounded by the +given indices from the given string. + +In \METAFUN\ we provide a few more functions (you can take a look in \type +{mp-tool.mp} to see how they are defined. You need to be aware of very subtle +rounding errors. Normally these only show up when you reverse an operation. This +is a result from mapping to and from internal quantities. + +\starttabulate[|Tl|ml|] +\HL +\NC sqr(x) \NC x^2 \NC \NR +\NC log(x) \NC \log(x) \NC \NR +\NC ln(x) \NC \ln(x) \NC \NR +\NC exp(x) \NC {\rm e}^x \NC \NR +\NC pow(x, p) \NC x^p \NC \NR +\NC inv(x) \NC 1/x \NC \NR +\HL +\stoptabulate + +The following sine and cosine functions take radians instead of angles in +degrees. + +\starttabulate[|Tl|Tl|Tl|] +\HL +\NC sin(x) \NC asin(x) \NC invsin(x) \NC \NR +\NC cos(x) \NC acos(x) \NC invcos(x) \NC \NR +\HL +\stoptabulate + +There are no tangent functions, so we provide both the radian and degrees +versions: + +\starttabulate[|Tl|Tl|] +\HL +\NC tan(x) \NC tand(x) \NC \NR +\NC cot(x) \NC cotd(x) \NC \NR +\HL +\stoptabulate + +Here are a couple of hyperbolic functions. + +\starttabulate[|Tl|Tl|] +\HL +\NC sinh(x) \NC asinh(x) \NC \NR +\NC cosh(x) \NC acosh(x) \NC \NR +\HL +\stoptabulate + +We end with a few additional string converters. + +\starttabulate[|Tl|l|] +\HL +\NC ddecimal x \NC decimal representation of a pair \NC \NR +\NC dddecimal x \NC decimal representation of a color \NC \NR +\NC condition x \NC string representation of a boolean \NC \NR +\HL +\stoptabulate + +\stopsection + +\startsection[title={Grids}] + +\index{grids} +\index{axis} + +Some day you may want to use \METAPOST\ to draw a function like graphic. In the +regular \TEX\ distributions you will find a module \type {graph.mp} that provides +many ways to accomplish this. For the moment, \METAFUN\ does not provide advanced +features with respect to drawing functions, so this section will be relatively +short. + +When drawing a functions (for educational purposes) we need to draw a couple of +axis or a grid as well as a shape. Along the axis we can put labels. For this we +can use the \METAPOST\ package \type {format.mp}, but this does not integrate +that well into the way \METAFUN\ deals with text typeset by \TEX. + +For those who love dirty tricks and clever macros, close reading of the code in +\type {format.mp} may be worthwhile. The format macros in there use \TEX\ to +typeset the core components of a number, and use the dimensions of those +components to compose combinations of signs, numbers and superscripts. + +In \METAFUN\ we have the module \type {mp-form.mp} which contains most of the +code in \type {format.mp} but in a form that is a bit more suited for fine +tuning. This permits us to use either the composition method, or to fall back on +the \type {textext} method that is part of \METAFUN. That way we can also handle +fonts that have digits with different dimensions. Another \quote {change} +concerns the pattern separator. Instead of a \type {%} we use \type {@}; you can +choose to set another separator, but for embedded definitions \type {%} is +definitely a bad choice because \TEX\ sees it as a comment and ignores everything +following it. + +\startbuffer[grd] +drawoptions(withpen pencircle scaled 1pt withcolor .625yellow) ; + +draw hlingrid(0, 10, 1, 3cm, 3cm) ; +draw vlingrid(0, 10, 1, 3cm, 3cm) ; + +draw hlingrid(0, 10, 1, 3cm, 3cm) shifted ( 3.5cm,0) ; +draw vloggrid(0, 10, 1, 3cm, 3cm) shifted ( 3.5cm,0) ; + +draw hloggrid(0, 10, 1, 3cm, 3cm) shifted ( 7.0cm,0) ; +draw vlingrid(0, 10, 1, 3cm, 3cm) shifted ( 7.0cm,0) ; + +draw hloggrid(0, 10, 1, 3cm, 3cm) shifted (10.5cm,0) ; +draw vloggrid(0, 10, 1, 3cm, 3cm) shifted (10.5cm,0) ; +\stopbuffer + +\typebuffer[grd] + +\startlinecorrection[blank] +\processMPbuffer[grd] +\stoplinecorrection + +\startbuffer[grd] +drawoptions(withpen pencircle scaled 1pt withcolor .625yellow) ; + +draw hlingrid(0, 10, 1, 3cm, 3cm) slanted .5 ; +draw vlingrid(0, 10, 1, 3cm, 3cm) slanted .5 ; +\stopbuffer + +\typebuffer[grd] + +\startlinecorrection[blank] +\processMPbuffer[grd] +\stoplinecorrection + +Using macros like these often involves a bit of trial and error. The arguments to +these macros are as follows: + +\starttyping +hlingrid (Min, Max, Step, Length, Width) +vlingrid (Min, Max, Step, Length, Height) +hloggrid (Min, Max, Step, Length, Width) +vloggrid (Min, Max, Step, Length, Height) +\stoptyping + +The macros take the following text upto the semi||colon into account and return a +picture. We will now apply this knowledge to a more meaningful example. First we +draw a grid. + +You can use the grid drawing macros to produce your own paper, for instance using +the following mixed \TEX ||\METAFUN\ code: + +\typebuffer[gridpage] + +This produces a page (as in \in {figure} [fig:gridpage]) with a metric grid. If +you're hooked to the inch, you can set \type {unit := 1in}. If you want to +process this code, you need to wrap it into the normal document producing +commands: + +\starttyping +\setupcolors[state=start] + +\starttext + ... definitions ... +\stoptext +\stoptyping + +\placefigure + [page] + [fig:gridpage] + {Quick and dirty grid paper.} + {\typesetfile + [mfun-901.tex] + [page=1,height=.9\textheight]} + +\stopsection + +\startsection[title={Drawing functions}] + +Today there are powerful tools to draw functions on grids, but for simple +functions you can comfortably use \METAPOST. Let's first draw a simple +log||linear grid. + +\startbuffer[grd] +drawoptions(withpen pencircle scaled .25pt withcolor .5white) ; + +draw hlingrid (0, 20, .2, 20cm, 10cm) ; +draw vloggrid (0, 10, .5, 10cm, 20cm) ; + +drawoptions(withpen pencircle scaled .50pt) ; + +draw hlingrid (0, 20, 1, 20cm, 10cm) ; +draw vloggrid (0, 10, 1, 10cm, 20cm) ; +\stopbuffer + +\typebuffer[grd] + +To this grid we add some labels: + +\startbuffer[txt] +fmt_pictures := false ; % use TeX as formatting engine +textextoffset := ExHeight ; % a variable set by ConTeXt + +draw hlintext.lft(0, 20, 5, 20cm, "@3e") ; +draw vlogtext.bot(0, 10, 9, 10cm, "@3e") ; +\stopbuffer + +\typebuffer[txt] + +The arguments to the text placement macros are similar to the ones for drawing +the axes. Here we provide a format string. + +\starttyping +hlintext (Min, Max, Step, Length, Format) +vlintext (Min, Max, Step, Length, Format) +hlogtext (Min, Max, Step, Length, Format) +vlogtext (Min, Max, Step, Length, Format) +\stoptyping + +When drawing a smooth function related curve, you need to provide enough sample +points. The \type {function} macro will generate them for you, but you need to +make sure that for instance the maximum and minimum values are part of the +generated series of points. Also, a smooth curve is not always the right curve. +Therefore we provide three drawing modes: + +\starttabulate[|cT|l|] +\HL +\NC \bf method \NC \bf result \NC \NR +\HL +\NC 1 \NC a punked curve, drawn using \type {--} \NC \NR +\NC 2 \NC a smooth curve, drawn using \type {..} \NC \NR +\NC 3 \NC a tight curve, drawn using \type {...} \NC \NR +\HL +\stoptabulate + +If method~2 or~3 do not give the desired outcome, you can try a smaller step +combined with method~1. + +\startbuffer[log] +draw + function(1,"log(x)","x",1,10,1) xyscaled (10cm,2cm) + withpen pencircle scaled 5mm withcolor transparent(1,.5,yellow) ; + +draw + function(2,".5log(x)","x",1,10,1) xyscaled (10cm,2cm) + withpen pencircle scaled 5mm withcolor transparent(1,.5,blue) ; +\stopbuffer + +\typebuffer[log] + +\placefigure + [page] + {An example of a graphic with labels along the axes.} + {\doifmodeelse{screen} + {\scale[height=.85\textheight]{\processMPbuffer[grd,txt,log]}} + {\processMPbuffer[grd,txt,log]}} + +The first argument to the \type {function} macro specifies the drawing method. +The last three arguments are the start value, end value and step. The second and +third argument specify the function to be drawn. In this case the pairs \type +{(x,x)} and \type {(.5log(x),x)} are calculated. + +\startbuffer[gon] +textextoffset := ExHeight ; + +drawoptions(withpen pencircle scaled .50pt) ; + +draw hlingrid(-10, 10, 1, 10cm, 10cm) ; +draw vlingrid( 0, 20, 1, 10cm, 20cm) shifted (0,-10cm) ; + +drawoptions() ; + +draw + function(2,"x","sind(x)",0,360,10) xyscaled (1cm/36,10cm) + withpen pencircle scaled 5mm withcolor transparent(1,.5,blue) ; + +draw + function(2,"x","sin(x*pi)",0,epsed(2),.1) xyscaled (10cm/2,5cm) + withpen pencircle scaled 5mm withcolor transparent(1,.5,yellow) ; + +draw + function(2,"x","cosd(x)",0,360,10) xyscaled (1cm/36,10cm) + withpen pencircle scaled 5mm withcolor transparent(1,.5,red) ; + +draw + function(2,"x","cos(x*pi)",0,epsed(2),.1) xyscaled (10cm/2,5cm) + withpen pencircle scaled 5mm withcolor transparent(1,.5,green) ; +\stopbuffer + +\typebuffer[gon] + +\placefigure + [page] + {By using transparent colors, we don't have to calculate + and mark the common points: they already stand out.} + {\doifmodeelse{screen} + {\scale[height=.85\textheight]{\processMPbuffer[gon]}} + {\processMPbuffer[gon]}} + +In this example we draw sinus and cosine functions using degrees and radians. In +the case of radians the end points are not calculated due to rounding errors. In +such case you can use the \type {epsed} value, which gives slightly more +playroom. + +\startbuffer[mix] +draw function (1, "x", "sin(2x)" , 1, 10, .01) scaled 1.5cm + withpen pencircle scaled 1mm withcolor transparent(1,.5,red) ; +draw function (1, "x", "sin(2x*x)" , 1, 10, .01) scaled 1.5cm + withpen pencircle scaled 1mm withcolor transparent(1,.5,green) ; +draw function (1, "x", "sin(2x*x+x)", 1, 10, .01) scaled 1.5cm + withpen pencircle scaled 1mm withcolor transparent(1,.5,blue) ; +\stopbuffer + +\typebuffer[mix] + +Of course you can do without a grid. The next example demonstrates a nice +application of transparencies. + +\startlinecorrection[blank] +\processMPbuffer[mix] +\stoplinecorrection + +If we use the \type {exclusion} method for the transparencies, combined with no +transparency, we get the following alternative. + +\startbuffer[mix] +draw function (2, "x", "sin(x)" , 0, 2pi, pi/40) scaled 2cm + withpen pencircle scaled 5mm withcolor transparent("exclusion",1,red) ; +draw function (2, "x", "sin(2x)", 0, 2pi, pi/40) scaled 2cm + withpen pencircle scaled 5mm withcolor transparent("exclusion",1,green) ; +draw function (2, "x", "sin(3x)", 0, 2pi, pi/40) scaled 2cm + withpen pencircle scaled 5mm withcolor transparent("exclusion",1,blue) ; +\stopbuffer + +\typebuffer[mix] + +\startlinecorrection[blank] +\processMPbuffer[mix,wipe] +\stoplinecorrection + +The next alternative uses a larger step, and as a result (in drawing mode~2) +gives worse results. (Without the \type {epsed} it would have looked even worse +in the end points. + + \startbuffer[mix] +draw function (2, "x", "sin(x)" , 0, epsed(2pi), pi/10) scaled 2cm + withpen pencircle scaled 5mm withcolor transparent("exclusion",1,red) ; +draw function (2, "x", "sin(2x)", 0, epsed(2pi), pi/10) scaled 2cm + withpen pencircle scaled 5mm withcolor transparent("exclusion",1,green) ; +draw function (2, "x", "sin(3x)", 0, epsed(2pi), pi/10) scaled 2cm + withpen pencircle scaled 5mm withcolor transparent("exclusion",1,blue) ; +\stopbuffer + +\typebuffer[mix] + +\startlinecorrection[blank] +\processMPbuffer[mix,wipe] +\stoplinecorrection + +There are enough applications out there to draw nice functions, like gnuplot for +which Mojca Miklavec made a backend that works well with \CONTEXT. Nevertheless +it can be illustrative to explore the possibilities of the \CONTEXT, \LUATEX, +\METAPOST\ combination using functions. + +First of all you can use \LUA\ to make paths and this is used in some of the +debugging and tracing options that come with \CONTEXT. For instance, if you +process a document with + +\starttyping +context --timing yourdoc.tex +\stoptyping + +then you can afterwards process a file that is generated while processing this +document: + +\starttyping +context --extras timing yourdoc +\stoptyping + +This will give you a document with graphics that show where \LUATEX\ spent its +time on. Of course these graphics are generated with \METAPOST. + +There are a few helpers built in (and more might follow). For example: + +\startbuffer +draw + \ctxlua { + metapost.metafun.topath { + { x=1, y=1 }, + { x=1, y=3 }, + { 4, 1}, + "cycle" + } + } + xysized(4cm,3cm) + withpen pencircle scaled 1mm + withcolor .625 red ; +\stopbuffer + +\typebuffer + +The \type {topath} function takes a table of points or strings. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +You can pass a connector so + +\startbuffer +draw + \ctxlua { + metapost.metafun.topath ( + { + { x=1, y=1 }, + { x=1, y=3 }, + { 4, 1 }, + "cycle" + }, + "--" + ) + } + xysized(4cm,3cm) + withpen pencircle scaled 1mm + withcolor .625 red ; +\stopbuffer + +\typebuffer + +gives: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Writing such \LUA\ functions is no big deal. For instance we have available: + +\starttyping +function metapost.metafun.interpolate(f,b,e,s,c) + tex.write("(") + for i=b,e,(e-b)/s do + local d = loadstring ( + string.formatters["return function(x) return %s end"](f) + ) + if d then + d = d() + if i > b then + tex.write(c or "...") + end + tex.write(string.formatters["(%F,%F)"](i,d(i))) + end + end + tex.write(")") +end +\stoptyping + +An example of usage is: + +\startbuffer +draw + \ctxlua{metapost.metafun.interpolate( + "math.sin(x^2+2*x+math.sqrt(math.abs(x)))", + -math.pi/2,math.pi/2,100 + )} + xysized(6cm,3cm) + withpen pencircle scaled 1mm + withcolor .625 red ; +\stopbuffer + +\typebuffer + +And indeed we get some drawing: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Let's see what happens when we use less accuracy and a different connector: + +\startbuffer +draw + \ctxlua{metapost.metafun.interpolate( + "math.sin(x^2+2*x+math.sqrt(math.abs(x)))", + -math.pi/2,math.pi/2,10,"--" + )} + xysized(6cm,3cm) + withpen pencircle scaled 1mm + withcolor .625 red ; +\stopbuffer + +\typebuffer + +Now we get: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Of course we could extend this \LUA\ function with all kind of options and we +might even do that when we need it. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex b/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex new file mode 100644 index 000000000..9010fc403 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex @@ -0,0 +1,548 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-gadgets + +\environment metafun-environment + +\startchapter[title={Shapes, symbols and buttons}] + +\startintro + +One can use \METAPOST\ to define symbols and enhance buttons. Here we introduce +some of the gadgets that come with \CONTEXT, as well as explain how to integrate +such gadgets yourself. + +\stopintro + +\startsection[title={Interfacing to \TEX}] + +\index {interfacing} + +\startbuffer[a] +\setupMPvariables + [EnglishRule] + [height=1ex, + width=\availablehsize, + color=darkgray] + +\startuniqueMPgraphic{EnglishRule}{height,width,color} + numeric height ; height = \MPvar{height} ; + x1 = 0 ; x3 = \MPvar{width} ; x2 = x4 = .5x3 ; + y1 = y3 = 0 ; y2 := -y4 = height/2 ; + fill z1 .. z2 .. z3 & z3 .. z4 .. z1 & cycle + withcolor \MPvar{color} ; +\stopuniqueMPgraphic +\stopbuffer + +\startbuffer[b] +\defineblank + [EnglishRule] + [medium] + +\unexpanded\def\EnglishRule + {\start + \dontcomplain + \startlinecorrection[EnglishRule] + \noindent \reuseMPgraphic{EnglishRule} + \stoplinecorrection + \stop} +\stopbuffer + +\getbuffer[a,b] + +In the early days of \METAPOST\ support in \CONTEXT, Tobias Burnus asked me if it +was possible to define English rules. What exactly does an english rule look +like? Here is one: + +\EnglishRule + +As you can see, such a rule has to adapt itself to the current text width, +normally \type {\hsize} in \TEX, or on request \type {\availablehsize} in +\CONTEXT. We need to set the height to a reasonable size, related to the font +size, and we also need to take care of proper spacing. Of course we want to run +\METAPOST\ as less times as possible, so we need to use unique graphics. Let's +start with the graphic. + +\typebuffer[a] + +As you can see, we pass two arguments to the graphic definition. The first +argument is the name, the second argument is a comma separated list of variables. +This list serves two purposes. First this list is used to create a unique profile +for the graphic. This means that when we change the value of a variable, a new +graphic is generated that reflects the change. A second purpose of the list is to +convert \TEX\ data structures into \METAPOST\ ones, especially dimensions and +colors. The graphic itself is not that spectacular. We use \type {&} because we +don't want smooth connections. + +\typebuffer[b] + +When setting the variables, we used \type {\availablehsize}. We need to use \type +{\noindent}, a rather familiar \TEX\ primitive, that we use here to start a non +indented paragraph, being the graphic. The line correction is needed to get the +spacing around the rule (graphic) right. We pass a blank skip identifier that is +mapped to a convenient medium skip. + +\startbuffer[c] +Why is this called an English line? + +\startnarrower + \EnglishRule + Is it because they cannot draw a straight one? This could be true + after a few strong beers, but then, how do Germans draw a line? + \EnglishRule +\stopnarrower +\stopbuffer + +\typebuffer[c] + +As expected, the rule adapts itself to the current width of the text. The height +of the rule in the middle matches the height of a character with no ascenders and +descenders. + +\getbuffer[c] + +\stopsection + +\startsection[title={Random graphics}] + +\index{randomization} + +\startbuffer[a] +\startuseMPgraphic{fuzzycount} + begingroup + save height, vstep, hsize, span, drift, d, cp ; + height := 3/ 4 * \the \bodyfontsize * \currentfontscale ; + span := 1/ 3 * height ; + drift := 1/10 * height ; + hsize := \the\hsize ; + vstep := \the\lineheight ; + xmax := hsize div 5span ; + pickup pencircle scaled (1/12 * height) ; + def d = (uniformdeviate drift) enddef ; + for i := 1 upto \MPvar{n} : + xpos := ((i-1) mod (5*xmax))*span ; + ypos := ((i-1) div (5*xmax))*vstep ; + draw + if (i mod 5)=0 : ((-d-4.5span,d)--(+d-0.5span,height-d)) + else : ((-d,+d)--(+d,height-d)) fi + shifted (xpos,-ypos+d-drift) ; + endfor; + picture cp ; cp := currentpicture ; + if (ypart ulcorner cp - ypart llcorner cp) <= vstep : + setbounds currentpicture to + (llcorner cp shifted (0,-ypart llcorner cp) -- + lrcorner cp shifted (0,-ypart lrcorner cp) -- + urcorner cp -- ulcorner cp -- cycle) ; + fi + endgroup ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[b] +\useMPgraphic{fuzzycount}{n=1001} +\stopbuffer + +Given enough time and paper, we can probably give you some + +\startlinecorrection[blank] +\getbuffer[a,b] +\stoplinecorrection + +reasons why \METAPOST\ is fun. To mention a few: you can enhance the layout with +graphic ornaments, you can tune your graphics at runtime, and simple high quality +graphics can be very effective. + +\startbuffer[c] +\startuseMPgraphic{fuzzycount} + begingroup + save height, span, drift, d, cp ; + height := 3/ 5 * \baselinedistance ; + span := 1/ 3 * height ; + drift := 1/10 * height ; + pickup pencircle scaled (1/12 * height) ; + def d = (uniformdeviate drift) enddef ; + for i := 1 upto \MPvar{n} : + draw + if (i mod 5)=0 : ((-d-4.5span,d)--(+d-0.5span,height-d)) + else : ((-d,+d)--(+d,height-d)) fi + shifted (span*i,d-drift) ; + endfor; + picture cp ; cp := currentpicture ; % for readability + setbounds currentpicture to + (llcorner cp shifted (0,-ypart llcorner cp) -- + lrcorner cp shifted (0,-ypart lrcorner cp) -- + urcorner cp -- ulcorner cp -- cycle) ; + endgroup ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[d] +\setupMPvariables[fuzzycount][n=10] +\stopbuffer + +\getbuffer[c,d] + +The previous graphics draws exactly 1001 lines in a scratch||numbers||in||a||wall +fashion. In 1998, the \NTG\ did a survey among its members, and in the report, we +used this fuzzy counter to enhance the rather dull tables. + +\startbuffer +\starttabulate[|l|c|l|] +\HL +\NC system \NC \% \NC \# users \NC\NR +\HL +\NC Atari \NC 10.4 \NC \useMPgraphic{fuzzycount}{n=11} \NC\NR +\NC MSDOS \NC 49.1 \NC \useMPgraphic{fuzzycount}{n=52} \NC\NR +\NC OS/2 \NC ~9.4 \NC \useMPgraphic{fuzzycount}{n=10} \NC\NR +\NC MacOS \NC ~5.7 \NC \useMPgraphic{fuzzycount}{n= 6} \NC\NR +\NC UNIX \NC 51.9 \NC \useMPgraphic{fuzzycount}{n=55} \NC\NR +\NC WINDOWS \NC 64.2 \NC \useMPgraphic{fuzzycount}{n=68} \NC\NR +\HL +\stoptabulate +\stopbuffer + +\placetable + [here][tab:fuzzy] + {Operating system (n=106).}{\getbuffer} + +\in {Table} [tab:fuzzy] demonstrates how scratch numbers can be used. An +interesting side effect is that when you look long enough to these kind of +graphics, it looks like the lines are no longer horizontal. This table is defined +as follows: + +\typebuffer + +You will notice that we pass a variable to the graphic using a second argument. +We can access this variable with \type {\MPvar}. The graphic is defined as usable +graphic, because we want to generate a unique random one each time. + +\typebuffer[c] + +The core of the macro is the \type {for} loop. Within this loop, we draw groups +of four plus one lines. The draw path's look a bit complicated, but this has to +do with the fact that a \type {mod} returns $0-4$ while we like to deal with +$1-5$. + +The height adapts itself to the height of the line. The bounding box correction +at the end ensures that the baseline is consistent and that the random vertical +offsets fall below the baseline. + +Because we want to be sure that \type {n} has a value, we preset it by saying: + +\typebuffer[d] + +In the table, it makes sense to adapt the drawing to the lineheight, but a more +general solution is to adapt the height to the fontsize. + +\starttyping +height := 3/ 4 * \the \bodyfontsize * \currentfontscale ; +\stoptyping + +\getbuffer[a] + +In the table we called the graphic directly, but how about making it available as +a conversion macro? In \CONTEXT\ this is not that hard: + +\startbuffer +\def\fuzzycount#1{{\tx\useMPgraphic{fuzzycount}{n=#1}}} +\defineconversion[fuzzy][\fuzzycount] +\stopbuffer + +\typebuffer \getbuffer + +Because such a counter should not be that large, we use \type {\tx} to switch to +a smaller font. This also demonstrates how the graphic adapts itself to the font +size. + +We can now use this conversion for instance in an itemize. To save space we use +three columns and no white space between the lines. The \type {2*broad} directive +makes sure that we have enough room for the number. + +\startbuffer +\startitemize[fuzzy,pack,2*broad,columns,three] +\item one \item two \item three +\item four \item five \item six +\item seven \item eight \item nine +\stopitemize +\stopbuffer + +\getbuffer + +\typebuffer + +A careful reader will have noticed that the previous definition of the fuzzy +counter drawing is not suited to generate the graphics we started with. + +\typebuffer[b] + +This time we want to limit the width to the current \type {\hsize}. We only need +to add a few lines of code. Watch how we don't recalculate the bounding box when +more lines are used. + +\typebuffer[a] + +\stopsection + +\startsection[title={Graphic variables}] + +\index{graphics+variables} +\index{variables} + +In the previous sections we have seen that we can pass information to the graphic +by means of variables. How exactly does this mechanism work? + +\startbuffer[def] +\setupMPvariables[smile][type=1,height=1.25ex,color=darkred] + +\startuniqueMPgraphic{smile}{type,height,color} + numeric size ; size := \MPvar{height} ; + drawoptions(withcolor \MPvar{color}) ; + pickup pencircle xscaled (size/6) yscaled (size/12) ; + draw halfcircle rotated -90 scaled size ; + pickup pencircle scaled (size/4) ; + if \MPvar{type}=1 : + for i=-1,+1 : draw origin shifted (0,i*size/4) ; endfor ; + elseif \MPvar{type}=2 : + for i=-1,+1 : draw origin shifted (-size/2,i*size/4) ; endfor ; + pickup pencircle scaled (size/6) ; + draw (size/4,0) -- (-size/4,0) ; + fi ; +\stopuniqueMPgraphic +\stopbuffer + +\startbuffer[sym] +\definesymbol[smile] [\uniqueMPgraphic{smile}{type=1}] +\definesymbol[smilemore][\uniqueMPgraphic{smile}{type=2}] +\stopbuffer + +\startbuffer[exa] +Say it with a \symbol [smile]\ or maybe even a \symbol +[smilemore], although seeing too many \dorecurse {10} +{\symbol [smile]\ } \unskip in one text may make you cry. +\stopbuffer + +\getbuffer[def,sym] + +A nice application of setting up variables for a specific graphic (or class of +graphics) is the following. In an email message the author can express his own or +the readers expected emotions with so called smilies like: \symbol [smile]. If +you want them in print, you can revert to combinations of characters in a font, +but as a \TEX\ user you may want to include nicer graphics. + +A convenient way to implement these is to make them into symbols, one reason +being that in that case they will adapt themselves to the current font size. + +\typebuffer[exa] \getbuffer[exa] + +Because we want an efficient implementation, we will use unique graphics, because +these will only be generated when the circumstances change. + +\typebuffer[sym] + +The definition itself then becomes: + +\typebuffer[def] + +We can now change some characteristics of the smilies without the need to +redefine the graphic. + +\startbuffer[set] +\setupMPvariables[smile][height=1ex,color=darkred] +\stopbuffer + +\typebuffer[set] + +\getbuffer[set,exa] + +In order to keep the smilies unique there is some magic involved, watch the +second argument in the next line: + +\starttyping +\startuniqueMPgraphic{smile}{type,height,color} +\stoptyping + +Because unique graphics often are used in backgrounds, its uniqueness is +determined by the overlay characteristics. In our case however the uniqueness is +determined by the smilies type, height and color. By explicitly specifying these, +we make sure that they count in the creation of the uniqueness stamp. + +\startbuffer[exa] +\midaligned{\switchtobodyfont[60pt]\symbol[smile]} +\stopbuffer + +\typebuffer[exa] + +Because we use the ex||height, the previous call works as expected. + +\startlinecorrection[blank] +\getbuffer[exa] +\stoplinecorrection + +\stopsection + +\startsection[title={Shape libraries}] + +\index{graphics+libraries} + +Unfortunately it takes some effort to define graphics, attach them to an overlay, +and invoke the background. However, the good news is that since in many cases we +want a consistent layout, we only have to do it once. The next table has some +hashed backgrounds. (More information about how to define tables can be found in +the \CONTEXT\ documentation and Up||To||Date documents.) + +\startbuffer +\bTABLE[frame=off,meta:hash:linecolor=darkyellow,offset=3ex] + \bTR + \bTD[background=meta:hash:right] right \eTD + \bTD[background=meta:hash:left] left \eTD + \bTD[background=meta:hash:horizontal] horizontal \eTD + \bTD[background=meta:hash:vertical] vertical \eTD + \eTR +\eTABLE +\stopbuffer + +\getbuffer[shape-a,shape-b,shape-c] + +\placetable + {A hashed table.} + {\getbuffer} + +This table is defined as: + +\typebuffer + +The graphics themselves are defined in a \METAPOST\ module. In this particular +example, the macro \type {some_hash} is defined in the file \type {mp-back.mp}. +This macro takes six arguments: + +\starttyping +some_hash (width, height, linewidth, linecolor, angle, gap) ; +\stoptyping + +Because we don't want to define a specific overlay for each color and linewidth, +we will use variables in the definition of the unique graphic. + +\typebuffer[shape-a] + +These variables are preset using \type {\setupMPvariables}: + +\typebuffer[shape-b] + +The last step in this process is to define the different +alternatives as overlays: + +\typebuffer[shape-c] + +As we can see in the definition of the table, we can pass settings to the \type +{\bTABLE} command. Actually, we can pass such settings to each command that +supports backgrounds, or more precisely \type {\framed}. \in {Table} [tab:hashes] +is for instance defined as: + +\startbuffer +\bTABLE[frame=off,meta:hash:linewidth=.4pt,align=middle,offset=2ex] + \bTR + \bTD[background={meta:hash:left,meta:hash:right}, + meta:hash:linecolor=darkyellow] + left \par \& \par right \eTD + \bTD[background={meta:hash:horizontal,meta:hash:vertical}, + meta:hash:linecolor=darkred] + horizontal \par \& \par vertical \eTD + \eTR +\eTABLE +\stopbuffer + +\typebuffer + +The long names are somewhat cumbersome, but in that way we can prevent name +clashes. Also, since the \METAPOST\ interface is english, the variables are also +english. + +\placetable + [here][tab:hashes] + {A double hashed table.} + {\getbuffer} + +\stopsection + +\startsection[title={Symbol collections}] + +\index{graphics+symbols} +\index{symbols} + +In \CONTEXT, a symbol can be defined without much coding. The advantage of using +symbols is that you can redefine them depending on the situation. So, + +\starttyping +\definesymbol [yes] [\em Yes!] +\stoptyping + +creates a symbol, that lets \type {\symbol[yes]} expand into {\em Yes!} Since +nearly anything can be a symbol, we can also say: + +\starttyping +\definesymbol [yes] [\mathematics{\star}] +\stoptyping + +or even the already defined symbol \symbol[star], by saying: + +\starttyping +\definesymbol [yes] [{\symbol[star]}] +\stoptyping + +It may be clear that we can use a graphic as well: + +\typebuffer[symb-c] + +Since we have collected some nice buttons in a \METAPOST\ file already, we can +use a rather simple definition: + +\typebuffer[symb-a] + +This leaves a few settings: + +\typebuffer[symb-b] + +These symbols are collected in \in {table} [tab:symbols], and are called up with +the \CONTEXT\ commands like \type {\symbol[menu:left]}. If needed, we can collect +these button symbols in a so called symbol set, which permits us to instantly +switch between sets with similar symbols. + +\startbuffer +\bTABLE[frame=off,width=36pt,align=middle] + \bTR \bTD \dontleavehmode \symbol[menu:left] \eTD + \bTD \dontleavehmode \symbol[menu:right] \eTD + \bTD \dontleavehmode \symbol[menu:list] \eTD + \bTD \dontleavehmode \symbol[menu:index] \eTD + \bTD \dontleavehmode \symbol[menu:person] \eTD + \bTD \dontleavehmode \symbol[menu:stop] \eTD + \bTD \dontleavehmode \symbol[menu:info] \eTD + \bTD \dontleavehmode \symbol[menu:down] \eTD + \bTD \dontleavehmode \symbol[menu:up] \eTD + \bTD \dontleavehmode \symbol[menu:print] \eTD \eTR + \bTR \bTD left \eTD + \bTD right \eTD + \bTD list \eTD + \bTD index \eTD + \bTD person \eTD + \bTD stop \eTD + \bTD info \eTD + \bTD down \eTD + \bTD up \eTD + \bTD print \eTD \eTR +\eTABLE +\stopbuffer + +\getbuffer[symb-a,symb-b,symb-c] + +\placetable + [here][tab:symbols] + {A collection of button symbols.} + {\getbuffer} + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-graphics.tex b/doc/context/sources/general/manuals/metafun/metafun-graphics.tex new file mode 100644 index 000000000..79c5df0df --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-graphics.tex @@ -0,0 +1,21 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-graphics + +\environment metafun-environment + +\startchapter[title={Example graphics}] + +\startintro + +In this chapter we will show some of the graphics that we made the last few years +using \METAPOST. They give an impression of what kind of non||mathematical +drawings can be made. + +\stopintro + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-index.tex b/doc/context/sources/general/manuals/metafun/metafun-index.tex new file mode 100644 index 000000000..8be313d85 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-index.tex @@ -0,0 +1,25 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-index + +\environment metafun-environment + +\startchapter[reference=index,title={Index}] + + \startcolumns + \placeregister[index] + \stopcolumns + +\stopchapter + +% \startchapter[reference=commands,title={Commands}] +% +% \startcolumns +% \placeregister[command] +% \stopcolumns +% +% \stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-introduction.tex b/doc/context/sources/general/manuals/metafun/metafun-introduction.tex new file mode 100644 index 000000000..b519055c0 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-introduction.tex @@ -0,0 +1,101 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-introduction + +\environment metafun-environment + +\starttitle[title={Introduction}] + +This document is about \METAPOST\ and \TEX. The former is a graphic programming +language, the latter a typographic programming language. However, in this +document we will not focus on real programming, but more on how we can interface +between those two languages. We will do so by using \CONTEXT, a macro package +written in \TEX, in which support for \METAPOST\ is integrated in the core. The +\TEX\ macros are integrated in \CONTEXT, and the \METAPOST\ macros are bundled in +\METAFUN. + +When Donald Knuth wrote his typographical programming language \TEX\ he was in +need for fonts, especially mathematical fonts. So, as a side track, he started +writing \METAFONT, a graphical language. When you read between the lines in the +\METAFONT\ book and the source code, the name John Hobby is mentioned alongside +complicated formulas. It will be no surprise then, that, since he was tightly +involved in the development of \METAFONT, after a few years his \METAPOST\ showed +up. + +While its ancestor \METAFONT\ was originally targeted at designing fonts, +\METAPOST\ is more oriented to drawing graphics as used in scientific +publications. Since \METAFONT\ produced bitmap output, some of its operators make +use of this fact. \METAPOST\ on the other hand produces \POSTSCRIPT\ code, which +means that it has some features not present in \METAFONT\ and vice versa. + +With \METAFUN\ I will demonstrate that \METAPOST\ can also be used, or misused, +for less technical drawing purposes. We will see that \METAPOST\ can fill in some +gaps in \TEX, especially its lack of graphic capabilities. We will demonstrate +that graphics can make a document more attractive, even if it is processed in a +batch processing system like \TEX. Most of all, we will see that embedding +\METAPOST\ definitions in the \TEX\ source enables a smooth communication between +both programs. + +The best starting point for using \METAPOST\ is the manual written by its author +John Hobby. You can find this manual at every main \TEX\ repository. Also, a copy +of the \METAFONT\ book from Donald Knuth is worth every cent, if only because it +will give you the feeling that many years of graphical fun lays ahead. + +In this \METAFUN\ manual we will demonstrate how you can embed graphics in a +\TEX\ document, but we will also introduce most of the features of \METAPOST. For +this reason you will see a lot of \METAPOST\ code. For sure there are better +methods to solve problems, but I have tried to demonstrate different methods and +techniques as much as possible. + +I started using \METAPOST\ long after I started using \TEX, and I never regret +it. Although I like \TEX\ very much, I must admit that sometimes using \METAPOST\ +is even more fun. Therefore, before we start exploring both in depth, I want to +thank their creators, Donald Knuth and John Hobby, for providing me these +fabulous tools. Of course I also need to thank \THANH, for giving the \TEX\ +community \PDFTEX, as well as providing me the hooks I considered necessary for +implementing some of the features presented here. In the meantime Taco Hoekwater +has created the \METAPOST\ library so that it can be an integral component of +\LUATEX. After that happened, the program was extended to deal with more than one +number implementation: in addition to scaled integers we now can switch to floats +and arbitrary precision decimal or binary calculations. I myself prototyped a +simple but efficient \LUA\ script interface. With Luigi Scarso, who is now the +maintainer of \METAPOST, we keep improving the system, so who knows what will +show up next. + +I also want to thank David Arnold and Ton Otten for their fast proofreading, for +providing me useful input, and for testing the examples. Without David's patience +and help, this document would be far from perfect English and less complete. +Without Ton's help, many small typos would have gone unnoticed. + +In the second version of this manual the content was been adapted to \CONTEXT\ +\MKIV\ that uses \LUATEX\ and the built in \METAPOST\ library. In the meantime +some \LUA\ has been brought into the game, not only to help construct graphics, +but also as a communication channel. In the process some extra features have been +added and some interfacing has been upgraded. The third version of this document +deals with that too. It makes no sense to maintain compatibility with \CONTEXT\ +\MKII, but many examples can be used there as well. In the meantime most +\CONTEXT\ users have switched to \MKIV, so this is no real issue. In the fourth +update some new features are presented and the discussion of obsolete ones have +been removed. + +The fifth update describes the \MPIV\ version of \METAFUN\ which brings some more +and improved functionality. Some examples are inspired from questions by users and +examples that Alan Braslau, Luigi Scarso and I made when testing new features and +macros. Some examples can be rewritten in a more efficient way but are kept as +they are. Therefore this manual presents different ways to solve problems. +Hopefully this is not too confusing. Numerous examples can be found in the other +manuals and test suite. + +\blank[big,samepage] + +\startlines +Hans Hagen +Hasselt NL +\currentdate[month,year] +\stoplines + +\stoptitle + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-layout.tex b/doc/context/sources/general/manuals/metafun/metafun-layout.tex new file mode 100644 index 000000000..2be7e19ff --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-layout.tex @@ -0,0 +1,990 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-layout + +\environment metafun-environment + +\startchapter[title={Enhancing the layout}] + +\startintro + +One of the most powerful and flexible commands of \CONTEXT\ is \type {\framed}. +We can use the background features of this command to invoke and position +graphics that adapt themselves to the current situation. Once understood, +overlays will become a natural part of the \CONTEXT\ users toolkit. + +\stopintro + +\startsection[title={Overlays}] + +\index{overlays} + +Many \CONTEXT\ commands support overlays. The term {\em overlay} is a bit +confusing, since such an overlay in most cases will lay under the text. However, +because there can be many layers on top of each other, the term suits its +purpose. + +When we want to put a \METAPOST\ graphic under some text, we go through a three +step process. First we define the graphic itself: + +\startbuffer +\startuniqueMPgraphic{demo circle} + path p ; + p := fullcircle xscaled \overlaywidth yscaled \overlayheight ; + fill p withcolor .85white ; + draw p withpen pencircle scaled 2pt withcolor .625red ; +\stopuniqueMPgraphic +\stopbuffer + +\typebuffer + +\getbuffer + +This graphic will adapt itself to the width and height of the overlay. Both \type +{\overlaywidth} and \type {\overlayheight} are macros that return a dimension +followed by a space. The next step is to register this graphic as an overlay. + +\startbuffer +\defineoverlay[demo circle][\uniqueMPgraphic{demo circle}] +\stopbuffer + +\typebuffer + +\getbuffer + +We can now use this overlay in any command that provides the \type {\framed} +functionality. Since this graphic is defined as unique, \CONTEXT\ will try to +reuse already calculated and embedded graphics when possible. + +\startbuffer +\framed[background=demo circle]{This text is overlayed.} +\stopbuffer + +\typebuffer + +The background can be set to \type {color}, \type {screen}, an overlay +identifier, like \typ {demo circle}, or a comma separated list of those. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +The \type {\framed} command automatically draws a ruled box, which can be quite +useful when debugging a graphic. However, in this case we want to turn the frame +off. + +\startbuffer +\framed + [background=demo circle,frame=off] + {This text is overlayed.} +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +In this case, it would have made sense to either set the \type {offset} to a +larger value, or to set \type {backgroundoffset}. In the latter case, the ellipse +is positioned outside the frame. + +The difference between the three offsets \type {offset}, \type {frameoffset} and +\type {backgroundoffset} is demonstrated in \in {figure} [fig:offsets]. While the +\type {offset} is added to the (natural or specified) dimensions of the content +of the box, the other two are applied to the frame and background and don't add +to the dimensions. + +In the first row we only set the \type {offset}, while in the second row, the +(text) offset is set to \type {3pt}. When not specified, the \type {offset} has a +comfortable default value of \type {.25ex} (some 25\% of the height of an~x). + +\startbuffer +\setupframed + [width=.3\textwidth, + background=demo circle] +\startcombination[3*3] + {\framed[offset=none] {\TeX}} {\tt offset=none} + {\framed[offset=overlay] {\TeX}} {\tt offset=overlay} + {\framed[offset=0pt] {\TeX}} {\tt offset=0pt} + {\framed[offset=1pt] {\TeX}} {\tt offset=1pt} + {\framed[offset=2pt] {\TeX}} {\tt offset=2pt} + {\framed[offset=4pt] {\TeX}} {\tt offset=4pt} + {\framed[offset=3pt] {\TeX}} {\tt offset=3pt} + {\framed[frameoffset=3pt] {\TeX}} {\tt frameoffset=3pt} + {\framed[backgroundoffset=3pt]{\TeX}} {\tt backgroundoffset=3pt} +\stopcombination +\stopbuffer + +\typebuffer + +\placefigure + [here][fig:offsets] + {The three offsets.} + {\getbuffer} + +As the first row in \in {figure} [fig:offsets] demonstrates, instead of a value, +one can pass a keyword. The \type {overlay} keyword implies that there is no +offset at all and that the lines cover the content. With \type {none} the frame +is drawn tight around the content. When the offset is set to \type {0pt} or more, +the text is automatically set to at least the height of a line. You can turn this +feature off by saying \type {strut=off}. More details can be found in the +\CONTEXT\ manual. + +In \in {figure} [fig:all offsets] we have set {offset} to \type {3pt}, \type +{frameoffset} to \type {6pt} and \type {backgroundoffset} to \type {9pt}. Both +the frame and background offset are sort of imaginary, since they don't +contribute to the size of the box. + +\startbuffer +\ruledhbox + {\framed + [offset=3pt,frameoffset=6pt,backgroundoffset=9pt, + background=screen,backgroundscreen=.85] + {Welcome in the hall of frame!}} +\stopbuffer + +\typebuffer + +\placefigure + [here][fig:all offsets] + {The three offsets.} + {\getbuffer} + +\stopsection + +\startsection[title={Overlay variables}] + +The communication between \TEX\ and embedded \METAPOST\ graphics takes place by +means of some macros. + +\starttabulate[|l|p|] +\HL +\NC overlay status macro \NC meaning \NC \NR +\HL +\NC \tex {overlaywidth} \NC the width of the graphic, as + calculated from the actual + width and background offset \NC \NR +\NC \tex {overlayheight} \NC the height of the graphic, as + calculated from the actual + height, depth and background + offset \NC \NR +\NC \tex {overlaydepth} \NC the depth of the graphic, if + available \NC \NR +\NC \tex {overlaycolor} \NC the background color, if given \NC \NR +\NC \tex {overlaylinecolor} \NC the color of the frame \NC \NR +\NC \tex {overlaylinewidth} \NC the width of the frame \NC \NR +\HL +\stoptabulate + +The dimensions of the overlay are determined by dimensions of the background, +which normally is the natural size of a \type {\framed}. When a background offset +is specified, it is added to \type {overlayheight} and \type {overlaywidth}. + +Colors can be converted by \type {\MPcolor} and in addition to the macros +mentioned, you can use all macros that expand into a dimension or dimen register +prefixed by the \TEX\ primitive \type {\the} (this and other primitives are +explained in \quotation {The \TeX book}, by Donald Knuth). + +\stopsection + +\startsection[title={Stacking overlays}] + +A background can be a gray scale (\type {screen}), a color (\type {color}), a +previously defined overlay identifier, or any combination of these. The next +assignments are therefore valid: + +\starttyping +\framed[background=color,backgroundcolor=red]{...} +\framed[background=screen,backgroundscreen=.8]{...} +\framed[background=circle]{...} +\framed[background={color,cow},backgroundcolor=red]{...} +\framed[background={color,cow,grid},backgroundcolor=red]{...} +\stoptyping + +In the last three cases of course you have to define \type {circle}, \type {cow} +and \type {grid} as overlay. These items are packed in a comma separated list, +which has to be surrounded by \type {{}}. + +\stopsection + +\startsection[title={Foregrounds}] + +\startbuffer[a] +\startuniqueMPgraphic{backfore} + draw fullcircle + xscaled \overlaywidth yscaled \overlayheight + withpen pencircle scaled 2pt + withcolor .625yellow ; +\stopuniqueMPgraphic + +\defineoverlay[backfore][\uniqueMPgraphic{backfore}] +\stopbuffer + +\startbuffer[b] +\framed + [background=backfore,backgroundoffset=4pt] + {one, two, three, \unknown} +\stopbuffer + +\startbuffer[c] +\framed + [background={foreground,backfore},backgroundoffset=4pt] + {one, two, three, \unknown} +\stopbuffer + +The overlay system is actually a system of layers. Sometimes we are confronted +with a situation in which we want the text behind another layer. This can be +achieved by explicitly placing the foreground layer, as in \in {figure} +[fig:foreground]. + +\getbuffer[a] + +\placefigure + [here][fig:foreground] + {Foreground material moved backwards.} + {\setupframed[linewidth=1pt]% + \startcombination + {\getbuffer[b]} {frame on top layer} + {\getbuffer[c]} {frame on bottom layer} + \stopcombination} + +The graphic layer is defined as follows: + +\typebuffer[a] + +The two framed texts have a slightly different definition. The leftmost graphic +is defined as: + +\typebuffer[b] + +The rightmost graphic is specified as: + +\typebuffer[c] + +The current values of the frame color and frame width are passed to the overlay. +It often makes more sense to use colors defined at the document level, if only to +force consistency. + +\startbuffer +\startuniqueMPgraphic{super ellipse} + path p ; p := unitsquare + xscaled \overlaywidth yscaled \overlayheight + superellipsed .85 ; + pickup pencircle scaled \overlaylinewidth ; + fill p withcolor \MPcolor{\overlaycolor} ; + draw p withcolor \MPcolor{\overlaylinecolor} ; +\stopuniqueMPgraphic + +\defineoverlay[super ellipse][\uniqueMPgraphic{super ellipse}] +\stopbuffer + +\typebuffer \getbuffer + +This background demonstrates that a super ellipse is rather well suited as frame. + +\startbuffer +\framed + [background=super ellipse, + frame=off, + width=3cm, + align=middle, + framecolor=darkyellow, + rulethickness=2pt, + backgroundcolor=darkgray] + {\white This is a\\Super Ellipsed\\sentence.} +\stopbuffer + +\typebuffer + +Such a super ellipse looks quite nice and is a good candidate for backgrounds, +for which the superness should be at least~.85. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Typesetting graphics}] + +I have run into people who consider it kind of strange when you want to use \TEX\ +for non||mathematical typesetting. If you agree with them, you may skip this +section with your eyes closed. + +One of the \CONTEXT\ presentation styles (number 15, tagged as balls) stepwise +builds screens full of sentences, quotes or concepts, packages in balloons and +typesets them as a paragraph. We will demonstrate that \TEX\ can typeset graphics +using the following statement. + +% \let\processword\relax + +\startbuffer[lions] +\processwords{As you may know, \TEX's ambassador is a lion, while {\METAFONT} +is represented by a lioness. It is still unclear if they have a relationship, +but if so, and if a cub is born, may it enjoy \METAFUN.} +\stopbuffer + +\startquotation +\def\processwords#1{#1}\getbuffer[lions] +\stopquotation + +The low level \CONTEXT\ macro \type {\processwords} provides a mechanism to treat +the individual words of its argument. The macro is called as follows: + +\typebuffer[lions] + +In order to perform a task, you should also define a macro \type {\processword}, +which takes one argument. The previous quote was typeset with the following +definition in place: + +\starttyping +\def\processword#1{#1} +\stoptyping + +A slightly more complicated definition is the following: + +\startbuffer +\def\processword#1{\noindent\framed{#1}\space} +\stopbuffer + +\typebuffer \getbuffer + +We now get: + +\blank\getbuffer[lions]\blank + +If we can use \type {\framed}, we can also use backgrounds. + +\startbuffer +\def\processword#1% + {\noindent\framed[frame=off,background=lions]{#1} } +\stopbuffer + +\typebuffer \getbuffer + +We can add a supperellipsed frame using the following definition: + +\startbuffer +\startuniqueMPgraphic{lions a} + path p ; p := fullsquare + xyscaled (\overlaywidth,\overlayheight) superellipsed .85 ; + pickup pencircle scaled 1pt ; + fill p withcolor .850white ; draw p withcolor .625yellow ; +\stopuniqueMPgraphic + +\defineoverlay[lions][\uniqueMPgraphic{lions a}] +\stopbuffer + +\typebuffer \getbuffer + +\bgroup \blank \veryraggedright\getbuffer[lions]\unskip \blank \egroup + +\startbuffer +\startuseMPgraphic{lions b} + path p ; p := fullsquare + xyscaled (\overlaywidth,\overlayheight) randomized 5pt ; + pickup pencircle scaled 1pt ; + fill p withcolor .850white ; draw p withcolor .625yellow ; +\stopuseMPgraphic + +\defineoverlay[lions][\uniqueMPgraphic{lions b}] +\stopbuffer + +\typebuffer \getbuffer + +\bgroup \blank \veryraggedcenter\getbuffer[lions]\unskip \blank \egroup + +\startbuffer +\startuniqueMPgraphic{lions c} + path p ; p := fullsquare + xyscaled (\overlaywidth,\overlayheight) squeezed 2pt ; + pickup pencircle scaled 1pt ; + fill p withcolor .850white ; draw p withcolor .625yellow ; +\stopuniqueMPgraphic + +\defineoverlay[lions][\uniqueMPgraphic{lions c}] +\stopbuffer + +\typebuffer \getbuffer + +\bgroup \blank \veryraggedleft\getbuffer[lions]\unskip \blank \egroup + +These paragraphs were typeset with the following settings. + +\starttyping +\setupalign[broad, right] % == \veryraggedright +\setupalign[broad, middle] % == \veryraggedcenter +\setupalign[broad, left] % == \veryraggedleft +\stoptyping + +The \type {broad} increases the raggedness. We defined three different graphics +(a, b and c) because we want some to be unique, which saves some processing. Of +course we don't reuse the random graphics. In the definition of \type +{\processword} we have to use \type {\noindent} because otherwise \TEX\ will put +each graphic on a line of its own. Watch the space at the end of the macro. + +\stopsection + +\startsection[title={Graphics and macros}] + +Because \TEX's typographic engine and \METAPOST's graphic engine are separated, +interfacing between them is not as natural as you may expect. In \CONTEXT\ we +have tried to integrate them as much as possible, but using the interface is not +always as convenient as it should be. What method you follow, depends on the +problem at hand. + +The official \METAPOST\ way to embed \TEX\ code into graphics is to use \typ +{btex ... etex}. As soon as \CONTEXT\ writes the graphic data to the intermediate +\METAPOST\ file, it looks for these commands. When it has encountered an \type +{etex}, \CONTEXT\ will make sure that the text that is to be typeset by \TEX\ is +{\em not} expanded. This is what you may expect, because when you would embed +those commands in a stand||alone graphic, they would also not be expanded, if +only because \METAPOST\ does not know \TEX. With expansion we mean that \TEX\ +commands are replaced by their meaning (which can be quite extensive). + +{\em Users of \CONTEXT\ MKIV\ can skip the next paragraph}. + +When \METAPOST\ sees a \type {btex} command, it will consult a so called \type +{mpx} file. This file holds the \METAPOST\ representation of the text typeset by +\TEX. Before \METAPOST\ processes a graphic definition file, it first calls +another program that filters the \type {btex} commands from the source file, and +generates a \TEX\ file from them. This file is then processed by \TEX, and after +that converted to a \type {mpx} file. In \CONTEXT\ we let \TEXEXEC\ take care of +this whole process. + +Because the \typ {btex ... etex} commands are filtered from the raw \METAPOST\ +source code, they cannot be part of macro definitions and loop constructs. When +used that way, only one instance would be found, while in practice multiple +instances may occur. + +This drawback is overcome by \METAFUN's \type {textext} command. This command +still uses \typ {btex ... etex} but writes these commands to a separate job +related file each time it is used. \footnote {It took the author a while to find +out that there is a \METAPOST\ module called \type {tex.mp} that provides a +similar feature, but with the disadvantage that each text results in a call to +\TEX. Each text goes into a temporary file, which is then included and results in +\METAPOST\ triggering \TEX.} After the first \METAPOST\ run, this file is merged +with the original file, and \METAPOST\ is called again. So, at the cost of an +additional run, we can use text typeset by \TEX\ in a more versatile way. Because +\METAPOST\ runs are much faster than \TEX\ runs, the price to pay in terms of run +time is acceptable. Unlike \typ {btex ... etex}, the \TEX\ code in \type +{textext} command is expanded, but as long as \CONTEXT\ is used this is seldom a +problem, because most commands are somewhat protected. + +If we define a graphic with text to be typeset by \TEX, there is a good chance +that this text is not frozen but passes as argument. A \TEX||like solution for +passing arbitrary content to such a graphic is the following: \footnote {The \type +{\unexpanded} prefix makes the command robust for being passed as argument. It is not +to be confused with the primitive. We had this feature already when the primitive +showed up and it was considered to be inconvenient for other macro packages to adapt to +the \CONTEXT\ situation. So keep that in mind when you mix macro packages.} + +\startbuffer[def] +\unexpanded\def\RotatedText#1#2% + {\startuseMPgraphic{RotatedText} + draw btex #2 etex rotated #1 ; + \stopuseMPgraphic + \useMPgraphic{RotatedText}} +\stopbuffer + +\typebuffer[def] \getbuffer[def] + +This macro takes two arguments (the \type {#} identifies an +argument): + +\startbuffer[exa] +\RotatedText{15}{Some Rotated Text} +\stopbuffer + +\typebuffer[exa] + +The text is rotated over 15 degrees about the origin in a counterclockwise +direction. + +\startlinecorrection[blank] +\getbuffer[exa] +\stoplinecorrection + +In \CONTEXT\ we seldom pass settings like the angle of rotation in this manner. +You can use \type {\setupMPvariables} to set up graphic||specific variables. Such +a variable can be accessed with \type {\MPvar}. + +\startbuffer[def] +\setupMPvariables[RotatedText][rotation=90] + +\startuseMPgraphic{RotatedText} + draw textext{Some Text} rotated \MPvar{rotation} ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer[def] \getbuffer[def] + +An example: + +\startbuffer[exa] +\RotatedText{-15}{Some Rotated Text} +\stopbuffer + +\typebuffer[exa] + +\startlinecorrection[blank] +\getbuffer[exa] +\stoplinecorrection + +In a similar fashion we can isolate the text. This permits us to use the same +graphics with different settings. + +\startbuffer[def] +\setupMPvariables[RotatedText][rotation=270] + +\setMPtext{RotatedText}{Some Text} + +\startuseMPgraphic{RotatedText} + draw \MPbetex{RotatedText} rotated \MPvar{rotation} ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer[def] \getbuffer[def] + +This works as expected: + +\startbuffer[exa] +\RotatedText{165}{Some Rotated Text} +\stopbuffer + +\typebuffer[exa] + +\startlinecorrection[blank] +\getbuffer[exa] +\stoplinecorrection + +It is now a small step towards an encapsulating macro (we assume that you are +familiar with \TEX\ macro definitions). + +\startbuffer[def] +\def\RotatedText[#1]#2% + {\setupMPvariables[RotatedText][#1]% + \setMPtext{RotatedText}{#2}% + \useMPgraphic{RotatedText}} + +\setupMPvariables[RotatedText][rotation=90] + +\startuseMPgraphic{RotatedText} + draw \MPbetex{RotatedText} rotated \MPvar{rotation} ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer[def] \getbuffer[def] + +Again, we default to a 90 degrees rotation, and pass both the settings and text +in an indirect way. This method permits you to build complicated graphics and +still keep macros readable. + +\startbuffer[exa] +\RotatedText[rotation=240]{Some Rotated Text} +\stopbuffer + +\typebuffer[exa] + +\startlinecorrection[blank] +\getbuffer[exa] +\stoplinecorrection + +You may wonder why we don't use the variable mechanism to pass the text. The main +reason is that the text mechanism offers a few more features, one of which is +that it passes the text straight on, without the danger of unwanted expansion of +embedded macros. Using \type {\setMPtext} also permits you to separate \TEX\ and +\METAPOST\ code and reuse it multiple times (imagine using the same graphic in a +section head command). + +There are three ways to access a text defined with \type {\setMPtext}. Imagine +that we have the following definitions: + +\startbuffer +\setMPtext {1} {Now is this \TeX\ or not?} +\setMPtext {2} {See what happens here.} +\setMPtext {3} {Text streams become pictures.} +\stopbuffer + +\typebuffer \getbuffer + +The \type {\MPbetex} macro returns a \typ {btex ... etex} construct. The \type +{\MPstring} returns the text as a \METAPOST\ string, between quotes. The raw text +can be fetched with \type {\MPtext}. + +\startbuffer +\startMPcode + picture p ; p := \MPbetex {1} ; + picture q ; q := textext( \MPstring{2} ) ; + picture r ; r := thelabel("\MPtext {3}",origin) ; + + for i=p, boundingbox p : draw i withcolor .625red ; endfor ; + for i=q, boundingbox q : draw i withcolor .625yellow ; endfor ; + for i=r, boundingbox r : draw i withcolor .625white ; endfor ; + + currentpicture := currentpicture scaled 2 ; + draw origin + withpen pencircle scaled 5.0mm withcolor white ; + draw origin + withpen pencircle scaled 2.5mm withcolor black ; + draw boundingbox currentpicture + withpen pencircle scaled .1mm + dashed evenly ; +\stopMPcode +\stopbuffer + +\typebuffer + +The first two lines return text typeset by \TEX, while the last line leaves this +to \METAPOST. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +If you watch closely, you will notice that the first (red) alternative is +positioned with the baseline on the origin. + +\startbuffer +\startMPcode + picture p ; p := \MPbetex {1} ; + picture q ; q := textext.origin( \MPstring{2} ) ; + picture r ; r := thelabel.origin("\MPtext {3}",origin) ; + + for i=p, boundingbox p : draw i withcolor .625red ; endfor ; + for i=q, boundingbox q : draw i withcolor .625yellow ; endfor ; + for i=r, boundingbox r : draw i withcolor .625white ; endfor ; + + currentpicture := currentpicture scaled 2 ; + draw origin withpen pencircle scaled 5.0mm + withcolor white ; + draw origin withpen pencircle scaled 2.5mm + withcolor black ; + draw boundingbox currentpicture + withpen pencircle scaled .1mm + dashed evenly ; +\stopMPcode +\stopbuffer + +\typebuffer + +This draws: + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +This picture demonstrates that we can also position \type {textext}'s and \type +{label}'s on the baseline. For this purpose the repertoire of positioning +directives (\type {top}, \type {lft}, etc.) is extended with an \type {origin} +directive. Another extra positioning directive is \type {raw}. This one does not +do any positioning at all. + +\starttyping +picture q ; q := textext.origin( \MPstring{2} ) ; +picture r ; r := thelabel.origin("\MPtext {3}",origin) ; +\stoptyping + +We will now apply this knowledge of text inclusion in graphics to a more advanced +example. The next definitions are the answer to a question on the \CONTEXT\ +mailinglist with regards to framed texts with titles. + +\startbuffer[a] +\defineoverlay[FunnyFrame][\useMPgraphic{FunnyFrame}] + +\defineframedtext[FunnyText][frame=off,background=FunnyFrame] + +\def\StartFrame{\startFunnyText} +\def\StopFrame {\stopFunnyText } + +\def\FrameTitle#1% + {\setMPtext{FunnyFrame}{\hbox spread 1em{\hss\strut#1\hss}}} + +\setMPtext{FunnyFrame}{} % initialize the text variable +\stopbuffer + +\startbuffer[b] +\startuseMPgraphic{FunnyFrame} + picture p ; numeric w, h, o ; + p := textext.rt(\MPstring{FunnyFrame}) ; + w := OverlayWidth ; h := OverlayHeight ; o := BodyFontSize ; + p := p shifted (2o,h-ypart center p) ; draw p ; + drawoptions (withpen pencircle scaled 1pt withcolor .625red) ; + draw (2o,h)--(0,h)--(0,0)--(w,0)--(w,h)--(xpart urcorner p,h) ; + draw boundingbox p ; + setbounds currentpicture to unitsquare xyscaled(w,h) ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[c1] +\FrameTitle{Zapf (1)} + +\StartFrame +Coming back to the use of typefaces in electronic +publishing: many of the new typographers receive their +knowledge and information about the rules of typography from +books, from computer magazines or the instruction manuals +which they get with the purchase of a PC or software. +\StopFrame +\stopbuffer + +\getbuffer[a,b,c1] + +In this example, the title is positioned on top of the frame. Title and text are +entered as: + +\typebuffer[c1] + +The implementation is not that complicated and uses the frame commands that are +built in \CONTEXT. Instead of letting \TEX\ draw the frame, we use \METAPOST, +which we also use for handling the title. The graphic is defined as follows: + +\typebuffer[b] + +Because the framed title is partly positioned outside the main frame, and because +the main frame will be combined with the text, we need to set the boundingbox +explicitly. This is a way to create so called free figures, where part of the +figure lays beyond the area that is taken into account when positioning the +graphic. The shift + +\starttyping +... shifted (2o,h-ypart center p) +\stoptyping + +ensures that the title is vertically centered over the top line of the main box. + +The macros that use this graphic combine some techniques of defining macros, +using predefined \CONTEXT\ classes, and passing information to graphics. + +\typebuffer[a] + +There is a little bit of low level \TEX\ code involved, like a horizontal box +(\type {\hbox}) that stretches one em||space beyond its natural size (\type +{spread 1em}) with a centered text (two times \type {\hss}). Instead of applying +this spread, we could have enlarged the frame on both sides. + +\startbuffer[b] +\startuseMPgraphic{FunnyFrame} + picture p ; numeric o ; path a, b ; pair c ; + p := textext.rt(\MPstring{FunnyFrame}) ; + a := unitsquare xyscaled(OverlayWidth,OverlayHeight) ; + o := BodyFontSize ; + p := p shifted (2o,OverlayHeight-ypart center p) ; + drawoptions (withpen pencircle scaled 1pt withcolor .625red) ; + b := a randomized (o/2) ; + fill b withcolor .85white ; draw b ; + b := (boundingbox p) randomized (o/8) ; + fill b withcolor .85white ; draw b ; + draw p withcolor black; + setbounds currentpicture to a ; + \stopuseMPgraphic +\stopbuffer + +In the previous graphic we calculated the big rectangle taking the small one into +account. This was needed because we don't use a background fill. The next +definition does, so there we can use a more straightforward approach by just +drawing (and filling) the small rectangle on top of the big one. + +\typebuffer[b] \getbuffer[b] + +\startbuffer[c2] +\FrameTitle{Zapf (2)} + +\StartFrame +There is not so much basic instruction, as of now, as there +was in the old days, showing the differences between good +and bad typographic design. +\StopFrame +\stopbuffer + +\getbuffer[c2] + +Because we use a random graphic, we cannot guarantee beforehand that the left and +right edges of the small shape touch the horizontal lines in a nice way. The next +alternative displaces the small shape plus text so that its center lays on the +line. On the average, this looks better. + +\startbuffer[b] +\startuseMPgraphic{FunnyFrame} + picture p ; numeric o ; path a, b ; pair c ; + p := textext.rt(\MPstring{FunnyFrame}) ; + a := unitsquare xyscaled(OverlayWidth,OverlayHeight) ; + o := BodyFontSize ; + p := p shifted (2o,OverlayHeight-ypart center p) ; + drawoptions (withpen pencircle scaled 1pt withcolor .625red) ; + b := a randomized (o/2) ; + fill b withcolor .85white ; draw b ; + c := center p ; + c := b intersectionpoint (c shifted (0,-o)--c shifted(0,o)) ; + p := p shifted (c-center p) ; + b := (boundingbox p) randomized (o/8) ; + fill b withcolor .85white ; draw b ; + draw p withcolor black; + setbounds currentpicture to a ; + \stopuseMPgraphic +\stopbuffer + +\typebuffer[b] \getbuffer[b] + +\getbuffer[c2] + +Yet another definition uses super ellipsed shapes instead of random ones. We need +a high degree of superness (.95) in order to make sure that the curves don't +touch the texts. + +\startbuffer[b] +\startuseMPgraphic{FunnyFrame} + picture p ; numeric o ; path a, b ; pair c ; + p := textext.rt(\MPstring{FunnyFrame}) ; + o := BodyFontSize ; + a := unitsquare xyscaled(OverlayWidth,OverlayHeight) ; + p := p shifted (2o,OverlayHeight-ypart center p) ; + drawoptions (withpen pencircle scaled 1pt withcolor .625red) ; + b := a superellipsed .95 ; + fill b withcolor .85white ; draw b ; + b := (boundingbox p) superellipsed .95 ; + fill b withcolor .85white ; draw b ; + draw p withcolor black ; + setbounds currentpicture to a ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer[b] \getbuffer[b] + +\startbuffer[c3] +\FrameTitle{Zapf (3)} + +\StartFrame +Many people are just fascinated by their PC's tricks, and +think that a widely||praised program, called up on the +screen, will make everything automatic from now on. +\StopFrame +\stopbuffer + +\getbuffer[c3] + +There are quite some hard coded values in these graphics, like the linewidths, +offsets and colors. Some of these can be fetched from the \type {\framed} +environment either by using \TEX\ macros or dimensions, or by using their +\METAFUN\ counterparts. In the following table we summarize both the available +\METAPOST\ variables and their \TEX\ counterparts. They may be used +interchangeably. + +\starttabulate[|l|Tl|l|] +\HL +\NC \bf \METAPOST\ variable \NC \rm \bf \TEX\ command \NC \bf meaning \NC\NR +\HL +\NC OverlayWidth \NC \string\overlaywidth + \NC current width \NC\NR +\NC OverlayHeight \NC \string\overlayheight + \NC current height \NC\NR +\NC OverlayDepth \NC \string\overlayheight + \NC current depth (often zero) \NC\NR +\NC OverlayColor \NC \string\MPcolor\string{\string\overlaycolor\string} + \NC background color \NC\NR +\NC OverlayLineWidth \NC \string\overlaylinewidth + \NC width of the frame \NC\NR +\NC OverlayLineColor \NC \string\MPcolor\string{\overlaylinecolor\string} + \NC color of the frame \NC\NR +\NC BaseLineSkip \NC \string\the\string\baselineskip + \NC main line distance \NC\NR +\NC LineHeight \NC \string\the\string\baselineskip + \NC idem \NC\NR +\NC BodyFontSize \NC \string\the\string\bodyfontsize + \NC font size of the running text \NC\NR +\NC StrutHeight \NC \string\strutheight + \NC space above the baseline \NC\NR +\NC StrutDepth \NC \string\strutdepth + \NC space below the baseline \NC\NR +\NC ExHeight \NC 1ex + \NC height of an x \NC \NR +\NC EmWidth \NC 1em + \NC width of an m-dash \NC \NR +\HL +\stoptabulate + +\startbuffer[b] +\startuseMPgraphic{FunnyFrame} + picture p ; numeric o ; path a, b ; pair c ; + p := textext.rt(\MPstring{FunnyFrame}) ; + o := BodyFontSize ; + a := unitsquare xyscaled(OverlayWidth,OverlayHeight) ; + p := p shifted (2o,OverlayHeight-ypart center p) ; + pickup pencircle scaled OverlayLineWidth ; + b := a superellipsed .95 ; + fill b withcolor OverlayColor ; + draw b withcolor OverlayLineColor ; + b := (boundingbox p) superellipsed .95 ; + fill b withcolor OverlayColor ; + draw b withcolor OverlayLineColor ; + draw p withcolor black ; + setbounds currentpicture to a ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer[b] \getbuffer[b] + +\startbuffer[d] +\setupframedtexts + [FunnyText] + [backgroundcolor=lightgray, + framecolor=darkred, + rulethickness=2pt, + offset=\bodyfontsize, + before={\blank[big,medium]}, + after={\blank[big]}, + width=\textwidth] +\stopbuffer + +\getbuffer[d,c3] + +We used the following command to pass the settings: + +\typebuffer[d] + +In a real implementation, we should also take care of some additional spacing +before the text, which is why we have added more space before than after the +framed text. + +We demonstrated that when defining graphics that are part of the layout, you need +to have access to information known to the typesetting engine. Take \in {figure} +[fig:penalty]. The line height needs to match the font and the two thin +horizontal lines should match the {\em x}||height. We also need to position the +baseline, being the lowest one of a pair of lines, in such a way that it suits +the proportions of the line as specified by the strut. A strut is an imaginary +large character with no width. You should be aware of the fact that while \TEX\ +works its way top||down, in \METAPOST\ the origin is in the lower left corner. + +\startmode[screen] + +\placefigure + [page][fig:penalty] + {Penalty lines.} + {\typesetfile[mfun-902.tex][page=1,frame=on,height=.85\textheight]} + +\stopmode + +\startnotmode[screen] + +\placefigure + [here][fig:penalty] + {Penalty lines.} + {\typesetfile[mfun-902.tex][page=1,frame=on,height=.50\textheight]} + +\stopnotmode + +\typebuffer[handwrit] + +This code demonstrates the use of \type {LineHeight}, \type {ExHeight}, \type +{StrutHeight} and \type {StrutDepth}. We set the interline spacing to 1.5 so that +we get a bit more loose layout. The variables mentioned are set each time a +graphic is processed and thereby match the current font settings. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-lua.tex b/doc/context/sources/general/manuals/metafun/metafun-lua.tex new file mode 100644 index 000000000..da35cccde --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-lua.tex @@ -0,0 +1,1060 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +% this is an extension of about-lua + +\startcomponent mfun-lua + +\environment metafun-environment + +\startchapter[title={Lua}] + +\index{\LUA} + +\startintro + +Already for some years I have been wondering how it would be if we could escape +to \LUA\ inside \METAPOST, or in practice, use \MPLIB\ in \LUATEX. The idea is +simple: embed \LUA\ code in a \METAPOST\ file that gets run as soon as it's seen. +In case you wonder why \LUA\ code makes sense, imagine generating graphics using +external data. The capabilities of \LUA\ to deal with that is more flexible and +advanced than in \METAPOST. Of course we could generate a \METAPOST\ definition +of a graphic from data but often it makes more sense to do the reverse. I finally +found time and reason to look into this and in the following sections I will +describe how it's done. + +\stopintro + +\startsection[title=Introduction] + +\stopsection + +\startsection[title=The basics] + +The approach is comparable to \LUATEX's \type {\directlua}. That primitive can be +used to execute \LUA\ code and in combination with \type {tex.print} we can pipe +back strings into the \TEX\ input stream. There a complication is that that we +have to be able to operate under different so called catcode regimes: the meaning +of characters can differ per regime. We also have to deal with line endings in +special ways as they relate to paragraphs and such. In \METAPOST\ we don't have +that complication so getting back input into the \METAPOST\ input, we can do so +with simple strings. For that a mechanism similar to \type {scantokens} can be +used. That way we can return anything (including nothing) as long as \METAPOST\ +can interpret it and as long as it fulfils the expectations. + +\starttyping +numeric n ; n := scantokens("123.456") ; +\stoptyping + +A script is run as follows: + +\starttyping +numeric n ; n := runscript("return '123.456'") ; +\stoptyping + +This primitive doesn't have the word \type {lua} in its name so in principle any +wrapper around the library can use it as hook. In the case of \LUATEX\ the script +language is of course \LUA. At the \METAPOST\ end we only expect a string. How +that string is constructed is completely up to the \LUA\ script. In fact, the +user is completely free to implement the runner any way she or he wants, like: + +\starttyping +local function scriptrunner(code) + local f = loadstring(code) + if f then + return tostring(f()) + else + return "" + end +end +\stoptyping + +This is hooked into an instance as follows: + +\starttyping +local m = mplib.new { + ... + run_script = scriptrunner, + ... +} +\stoptyping + +Now, beware, this is not the \CONTEXT\ way. We provide print functions and other +helpers, which we will explain in the next section. + +\stopsection + +\startsection[title=Helpers] + +After I got this feature up and running I played a bit with possible interfaces +at the \CONTEXT\ (read: \METAFUN) end and ended up with a bit more advanced runner +where no return value is used. The runner is wrapped in the \type {lua} macro. + +\startbuffer +numeric n ; n := lua("mp.print(12.34567)") ; +draw textext(n) xsized 4cm withcolor darkred ; +\stopbuffer + +\typebuffer + +This renders as: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +In case you wonder how efficient calling \LUA\ is, don't worry: it's fast enough, +especially if you consider suboptimal \LUA\ code and the fact that we switch +between machineries. + +\startbuffer +draw image ( + lua("statistics.starttiming()") ; + for i=1 upto 10000 : draw + lua("mp.pair(math.random(-200,200),math.random(-50,50))") ; + endfor ; + setbounds currentpicture to fullsquare xyscaled (400,100) ; + lua("statistics.stoptiming()") ; +) withcolor darkyellow withpen pencircle scaled 1 ; +draw textext(lua("mp.print(statistics.elapsedtime())")) + ysized 50 withcolor darkred ; +\stopbuffer + +\typebuffer + +Here the line: + +\starttyping +draw lua("mp.pair(math.random(-200,200),math.random(-50,50))") ; +\stoptyping + +effectively becomes (for instance): + +\starttyping +draw scantokens "(25,40)" ; +\stoptyping + +which in turn becomes: + +\starttyping +draw scantokens (25,40) ; +\stoptyping + +The same happens with this: + +\starttyping +draw textext(lua("mp.print(statistics.elapsedtime())")) ... +\stoptyping + +This becomes for instance: + +\starttyping +draw textext(scantokens "1.23") ... +\stoptyping + +and therefore: + +\starttyping +draw textext(1.23) ... +\stoptyping + +We can use \type {mp.print} here because the \type {textext} macro can deal with +numbers. The next also works: + +\starttyping +draw textext(lua("mp.quoted(statistics.elapsedtime())")) ... +\stoptyping + +Now we get (in \METAPOST\ speak): + +\starttyping +draw textext(scantokens (ditto & "1.23" & ditto) ... +\stoptyping + +Here \type {ditto} represents the double quotes that mark a string. Of course, +because we pass the strings directly to \type {scantokens}, there are no outer +quotes at all, but this is how it can be simulated. In the end we have: + +\starttyping +draw textext("1.23") ... +\stoptyping + +What you use, \type {mp.print} or \type {mp.quoted} depends on what the expected +code is: an assignment to a numeric can best be a number or an expression +resulting in a number. + +This graphic becomes: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The runtime on my current machine is some 0.25 seconds without and 0.12 seconds +with caching. But to be honest, speed is not really a concern here as the amount +of complex \METAPOST\ graphics can be neglected compared to extensive node list +manipulation. With \LUAJITTEX\ generating the graphic takes 15\% less time. + +\startbuffer +numeric n ; n := lua("mp.print(1) mp.print('+') mp.print(2)") ; +draw textext(n) xsized 1cm withcolor darkred ; +\stopbuffer + +The three print command accumulate their arguments: + +\typebuffer + +As expected we get: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startbuffer +numeric n ; n := lua("mp.print(1,'+',2)") ; +draw textext(n) xsized 1cm withcolor darkred ; +\stopbuffer + +Equally valid is: + +\typebuffer + +This gives the same result: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Of course all kind of action can happen between the prints. It is also legal to +have nothing returned as could be seen in the 10.000 dot example: there the timer +related code returns nothing so effectively we have \type {scantokens("")}. Another +helper is \type {mp.quoted}, as in: + +\startbuffer +draw + textext(lua("mp.quoted('@0.3f'," & decimal n & ")")) + withcolor darkred ; +\stopbuffer + +\typebuffer + +This typesets \processMPbuffer. Watch the \type {@}. When no percent character is +found in the format specifier, we assume that an \type {@} is used instead. + +\startbuffer +\startluacode +table.save("demo-data.lua", + { + { 1, 2 }, { 2, 4 }, { 3, 3 }, { 4, 2 }, + { 5, 2 }, { 6, 3 }, { 7, 4 }, { 8, 1 }, + } +) +\stopluacode +\stopbuffer + +But, the real benefit of embedded \LUA\ is when we deal with data that is stored +at the \LUA\ end. First we define a small dataset: + +\typebuffer + +\getbuffer + +There are several ways to deal with this table. I will show clumsy as well as +better looking ways. + +\startbuffer +lua("MP = { } MP.data = table.load('demo-data.lua')") ; +numeric n ; +lua("mp.print('n := ',\#MP.data)") ; +for i=1 upto n : + drawdot + lua("mp.pair(MP.data[" & decimal i & "])") scaled cm + withpen pencircle scaled 2mm + withcolor darkred ; +endfor ; +\stopbuffer + +\typebuffer + +Here we load a \LUA\ table and assign the size to a \METAPOST\ numeric. Next we +loop over the table entries and draw the coordinates. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +We will stepwise improve this code. In the previous examples we omitted wrapper +code but here we show it: + +\startbuffer +\startluacode + MP.data = table.load('demo-data.lua') + function MP.n() + mp.print(#MP.data) + end + function MP.dot(i) + mp.pair(MP.data[i]) + end +\stopluacode + +\startMPcode + numeric n ; n := lua("MP.n()") ; + for i=1 upto n : + drawdot + lua("MP.dot(" & decimal i & ")") scaled cm + withpen pencircle scaled 2mm + withcolor darkred ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +So, we create a few helpers in the \type {MP} table. This table is predefined so +normally you don't need to define it. You may however decide to wipe it clean. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +You can decide to hide the data: + +\startbuffer +\startluacode + local data = { } + function MP.load(name) + data = table.load(name) + end + function MP.n() + mp.print(#data) + end + function MP.dot(i) + mp.pair(data[i]) + end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +It is possible to use less \LUA, for instance in: + +\startbuffer +\startluacode + local data = { } + function MP.loaded(name) + data = table.load(name) + mp.print(#data) + end + function MP.dot(i) + mp.pair(data[i]) + end +\stopluacode + +\startMPcode + for i=1 upto lua("MP.loaded('demo-data.lua')") : + drawdot + lua("MP.dot(",i,")") scaled cm + withpen pencircle scaled 4mm + withcolor darkred ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +Here we also omit the \type {decimal} because the \type {lua} macro is clever +enough to recognize it as a number. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +By using some \METAPOST\ magic we can even go a step further in readability: + +\startbuffer +\startMPcode{doublefun} + lua.MP.load("demo-data.lua") ; + + for i=1 upto lua.MP.n() : + drawdot + lua.MP.dot(i) scaled cm + withpen pencircle scaled 4mm + withcolor darkred ; + endfor ; + + for i=1 upto MP.n() : + drawdot + MP.dot(i) scaled cm + withpen pencircle scaled 2mm + withcolor white ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +Here we demonstrate that it also works ok in \type {double} mode, which makes +much sense when processing data from other sources. Watch how we omit the +type {lua.} prefix: the \type {MP} macro will deal with that. + +\startlinecorrection[blank] +\getbuffer +\stoplinecorrection + +So in the end we can simplify the code that we started with to: + +\starttyping +\startMPcode{doublefun} + for i=1 upto MP.loaded("demo-data.lua") : + drawdot + MP.dot(i) scaled cm + withpen pencircle scaled 2mm + withcolor darkred ; + endfor ; +\stopMPcode +\stoptyping + +\stopsection + +\startsection[title=Access to variables] + +The question with such mechanisms is always: how far should we go. Although +\METAPOST\ is a macro language it has properties of procedural languages. It also +has more introspective features at the user end. For instance, one can loop over +the resulting picture and manipulate it. This means that we don't need full +access to \METAPOST\ internals. However, it makes sense to provide access to +basic variables: \type {numeric}, \type {string}, and \type {boolean}. + +\startbuffer +draw textext(lua("mp.quoted('@0.15f',mp.get.numeric('pi')-math.pi)")) + ysized 1cm + withcolor darkred ; +\stopbuffer + +\typebuffer + +In double mode you will get zero printed but in scaled mode we definitely get a +difference: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\startbuffer +boolean b ; b := true ; +draw textext(lua("mp.quoted(mp.get.boolean('b') and 'yes' or 'no')")) + ysized 1cm + withcolor darkred ; +\stopbuffer + +In the next example we use \type {mp.quoted} to make sure that indeed we pass a +string. The \type {textext} macro can deal with numbers but an unquoted \type +{yes} or \type {no} is asking for problems. + +\typebuffer + +Especially when more text is involved it makes sense to predefine a helper in +the \type {MP} namespace if only because \METAPOST\ (currently) doesn't like +newlines in the middle of a string, so a \type {lua} call has to be on one line. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Here is an example where \LUA\ does something that would be close to impossible, +especially if more complex text is involved. + +% \enabletrackers[metapost.lua] + +\startbuffer +string s ; s := "ΤΕΧ" ; % "τεχ" +draw textext(lua("mp.quoted(characters.lower(mp.get.string('s')))")) + ysized 1cm + withcolor darkred ; +\stopbuffer + +\typebuffer + +As you can see here, the whole repertoire of helper functions can be used in +a \METAFUN\ definition. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title=The library] + +In \CONTEXT\ we have a dedicated runner, but for the record we mention the +low level constructor: + +\starttyping +local m = mplib.new { + ... + script_runner = function(s) return loadstring(s)() end, + script_error = function(s) print(s) end, + ..., +} +\stoptyping + +An instance (in this case \type {m}) has a few extra methods. Instead you can use +the helpers in the library. + +\starttabulate[|l|l|] +\HL +\NC \type {m:get_numeric(name)} \NC returns a numeric (double) \NC \NR +\NC \type {m:get_boolean(name)} \NC returns a boolean (\type {true} or \type {false}) \NC \NR +\NC \type {m:get_string (name)} \NC returns a string \NC \NR +\HL +\NC \type {mplib.get_numeric(m,name)} \NC returns a numeric (double) \NC \NR +\NC \type {mplib.get_boolean(m,name)} \NC returns a boolean (\type {true} or \type {false}) \NC \NR +\NC \type {mplib.get_string (m,name)} \NC returns a string \NC \NR +\HL +\stoptabulate + +In \CONTEXT\ the instances are hidden and wrapped in high level macros, so there +you cannot use these commands. + +\stopsection + +\startsection[title=\CONTEXT\ helpers] + +The \type {mp} namespace provides the following helpers: + +\starttabulate[|l|l|] +\HL +\NC \type {print(...)} \NC returns one or more values \NC \NR +\NC \type {pair(x,y)} + \type {pair(t)} \NC returns a proper pair \NC \NR +\NC \type {triplet(x,y,z)} + \type {triplet(t)} \NC returns an \RGB\ color \NC \NR +\NC \type {quadruple(w,x,y,z)} + \type {quadruple(t)} \NC returns an \CMYK\ color \NC \NR +\NC \type {format(fmt,...)} \NC returns a formatted string \NC \NR +\NC \type {quoted(fmt,...)} + \type {quoted(s)} \NC returns a (formatted) quoted string \NC \NR +\NC \type {path(t[,connect][,close])} \NC returns a connected (closed) path \NC \NR +\HL +\stoptabulate + +The \type {mp.get} namespace provides the following helpers: + +\starttabulate[|l|l|] +\HL +\NC \type {numeric(name)} \NC gets a numeric from \METAPOST \NC \NR +\NC \type {boolean(name)} \NC gets a boolean from \METAPOST \NC \NR +\NC \type {string(name)} \NC gets a string from \METAPOST \NC \NR +\HL +\stoptabulate + +\stopsection + +\startsection[title=Paths] + +In the meantime we got several questions on the \CONTEXT\ mailing list about turning +coordinates into paths. Now imagine that we have this dataset: + +\startbuffer[dataset] +10 20 20 20 -- sample 1 +30 40 40 60 +50 10 + +10 10 20 30 % sample 2 +30 50 40 50 +50 20 + +10 20 20 10 # sample 3 +30 40 40 20 +50 10 +\stopbuffer + +\typebuffer[dataset] + +In this case I've put the data in a buffer so that it can be shown +here as well as used in a demo. Watch how we can add comments. The +following code converts this into a table with three subtables. + +\startbuffer +\startluacode + MP.myset = mp.dataset(buffers.getcontent("dataset")) +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +We use the \type {MP} (user) namespace to store the table. Next we turn +these subtables into paths: + +\startbuffer +\startMPcode + for i=1 upto lua("mp.print(mp.n(MP.myset))") : + draw + lua("mp.path(MP.myset[" & decimal i & "])") + xysized (HSize-.25ExHeight,10ExHeight) + withpen pencircle scaled .25ExHeight + withcolor basiccolors[i]/2 ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +This gives: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +Instead we can fill the path in which case we also need to close it. The +\type {true} argument deals with that: + +\startbuffer +\startMPcode + for i=1 upto lua("mp.print(mp.n(MP.myset))") : + path p ; p := + lua("mp.path(MP.myset[" & decimal i & "],true)") + xysized (HSize,10ExHeight) ; + fill p + withcolor basiccolors[i]/2 + withtransparency (1,.5) ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +We get: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +\startbuffer +\startMPcode + for i=1 upto lua("mp.print(mp.n(MP.myset))") : + path p ; p := + lua("mp.path(MP.myset[" & decimal i & "])") + xysized (HSize,10ExHeight) ; + p := + (xpart llcorner boundingbox p,0) -- + p -- + (xpart lrcorner boundingbox p,0) -- + cycle ; + fill p + withcolor basiccolors[i]/2 + withtransparency (1,.25) ; + endfor ; +\stopMPcode +\stopbuffer + +The following makes more sense: + +\typebuffer + +So this gives: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +This (area) fill is so common that we have a helper for it: + +\startbuffer +\startMPcode + for i=1 upto lua("mp.size(MP.myset)") : + fill area + lua("mp.path(MP.myset[" & decimal i & "])") + xysized (HSize,5ExHeight) + withcolor basiccolors[i]/2 + withtransparency (2,.25) ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +So this gives: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +A variant call is the following: \footnote {Getting that to work properly in the +library was non||trivial as the loop variable \type {i} is an abstract nameless +variable at the \METAPOST\ end. When investigating this Luigi Scarso and I found out +that the internals of \METAPOST\ are not really geared for interfacing this way +but in the end it worked out well.} + +\startbuffer +\startMPcode + for i=1 upto lua("mp.size(MP.myset)") : + fill area + lua("mp.path(MP.myset[mp.get.numeric('i')])") + xysized (HSize,5ExHeight) + withcolor basiccolors[i]/2 + withtransparency (2,.25) ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +The result is the same: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +\startbuffer +\startluacode + MP.mypath = function(i) + return mp.path(MP.myset[mp.get.numeric(i)]) + end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\startMPcode + for i=1 upto lua("mp.size(MP.myset)") : + fill area + lua("MP.mypath('i')") + xysized (HSize,5ExHeight) + withcolor basiccolors[i]/2 + withtransparency (2,.25) ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +This snippet of \METAPOST\ code still looks kind of horrible so how can we make +it look better? Here is an attempt, First we define a bit more \LUA: + +\startbuffer +\startluacode +local data = mp.dataset(buffers.getcontent("dataset")) + +MP.dataset = { + Line = function(n) mp.path(data[n]) end, + Size = function() mp.size(data) end, +} +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +We can now make the \METAPOST\ look more natural. Of course this is possible +because in \METAFUN\ the \type {lua} macro does some extra work. + +\startbuffer +\startMPcode + for i=1 upto lua.MP.dataset.Size() : + path p ; p := + lua.MP.dataset.Line(i) + xysized (HSize-ExHeight,20ExHeight) ; + draw + p + withpen pencircle scaled .25ExHeight + withcolor basiccolors[i]/2 ; + drawpoints + p + withpen pencircle scaled ExHeight + withcolor basiccolors[i]/2 ; + endfor ; +\stopMPcode +\stopbuffer + +\typebuffer + +As expected, we get the desired result: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +Once we start making things look nicer and more convenient, we quickly end up +with helpers like the once in the next example. First we save some demo data +in files: + +\startbuffer +\startluacode + io.savedata("foo.tmp","10 20 20 20 30 40 40 60 50 10") + io.savedata("bar.tmp","10 10 20 30 30 50 40 50 50 20") +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +We load the data in datasets: + +\startbuffer +\startMPcode + lua.mp.datasets.load("foo","foo.tmp") ; + lua.mp.datasets.load("bar","bar.tmp") ; + fill area + lua.mp.datasets.foo.Line() + xysized (HSize/2-EmWidth-.25ExHeight,10ExHeight) + withpen pencircle scaled .25ExHeight + withcolor darkyellow ; + fill area + lua.mp.datasets.bar.Line() + xysized (HSize/2-EmWidth-.25ExHeight,10ExHeight) + shifted (HSize/2+EmWidth,0) + withpen pencircle scaled .25ExHeight + withcolor darkred ; +\stopMPcode +\stopbuffer + +\typebuffer + +Because the datasets are stores by name we can use them without worrying about +them being forgotten: + +\startlinecorrection[blank] \getbuffer \stoplinecorrection + +If no tag is given, the filename (without suffix) is used as tag, so the following is +valid: + +\starttyping +\startMPcode + lua.mp.datasets.load("foo.tmp") ; + lua.mp.datasets.load("bar.tmp") ; +\stopMPcode +\stoptyping + +The following methods are defined for a dataset: + +\starttabulate[|l|pl|] +\HL +\NC \type {method} \NC usage \NC \NR +\HL +\NC \type {Size} \NC the number of subsets in a dataset \NC \NR +\NC \type {Line} \NC the joined pairs in a dataset making a non|-|closed path \NC \NR +\NC \type {Data} \NC the table containing the data (in subsets, so there is always at least one subset) \NC \NR +\HL +\stoptabulate + +{\em In order avoid interference with suffix handling in \METAPOST\ the methods +start with an uppercase character.} + +\stopsection + +\startsection[title=Passing variables] + +You can pass variables from \METAPOST\ to \CONTEXT. Originally that happened via +a temporary file and so called \METAPOST\ specials. Nowadays it's done via \LUA. +Here is an example: + +\startbuffer +\startMPcalculation + +passvariable("version","1.0") ; +passvariable("number",123) ; +passvariable("string","whatever") ; +passvariable("point",(1.5,2.8)) ; +passvariable("triplet",(1/1,1/2,1/3)) ; +passvariable("quad",(1.1,2.2,3.3,4.4)) ; +passvariable("boolean",false) ; +passvariable("path",fullcircle scaled 1cm) ; +path p[] ; p[1] := fullcircle ; p[2] := fullsquare ; +passarrayvariable("list",p,1,2,1) ; % first last step +\stopMPcalculation +\stopbuffer + +\typebuffer + +\getbuffer + +We can visualize the result with + +\startbuffer +\startluacode +context.tocontext(metapost.variables) +\stopluacode +\stopbuffer + +\typebuffer + +\getbuffer + +In \TEX\ you can access these variables as follows: + +\startbuffer +\MPrunvar{version} +\MPruntab{quad}{3} +(\MPrunset{triplet}{,}) + +$(x,y) = (\MPruntab{point}{1},\MPruntab{point}{2})$ +$(x,y) = (\MPrunset{point}{,})$ +\stopbuffer + +\typebuffer + +This becomes: % we need a hack as we cross pages and variables get replace then + +\startlines +\getbuffer +\stoplines + +Here we passed the code between \type {\startMPcalculation} and \type +{\stopMPcalculation} which does not produce a graphic and therefore takes no +space in the flow. Of course it also works with normal graphics. + +\startbuffer +\startMPcode +path p ; p := fullcircle xyscaled (10cm,2cm) ; +path b ; b := boundingbox p ; +startpassingvariable("mypath") + passvariable("points",p) ; + startpassingvariable("metadata") + passvariable("boundingbox",boundingbox p) ; + stoppassingvariable ; +stoppassingvariable ; +fill p withcolor .625red ; +draw b withcolor .625yellow ; +\stopMPcode +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] + \getbuffer +\stoplinecorrection + +This time we get: + +\ctxlua{context.tocontext(metapost.variables)} + +You need to be aware of the fact that a next graphic resets the previous +variables. You can easily overcome that limitation by saving the variables (in +\LUA). It helps that when a page is being shipped out (which can involve +graphics) the variables are protected. You can push and pop variable sets with +\type {\MPpushvariables} and \type {\MPpopvariables}. Because you can nest +the \type {start}||\type{stop} pairs you can create quite complex indexed +and hashed tables. If the results are not what you expect, you can enable a +tracker to follow what gets passed: + +\starttyping +\enabletrackers[metapost.variables] +\stoptyping + +Serializing variables can be done with the \type {tostring} macro, for instance: + +\startbuffer +\startMPcode +message("doing circle",fullcircle); +draw fullcircle ; +\stopMPcode +\stopbuffer + +In this case the \type {tostring} is redundant as the message already does the +serialization. + +\stopsection + +\stopchapter + +% \startMPcode{doublefun} +% numeric n ; n := 123.456 ; +% lua("print('>>>>>>>>>>>> number',mp.get.number('n'))") ; +% lua("print('>>>>>>>>>>>> number',mp.get.boolean('n'))") ; +% lua("print('>>>>>>>>>>>> number',mp.get.string('n'))") ; +% boolean b ; b := true ; +% lua("print('>>>>>>>>>>>> boolean',mp.get.number('b'))") ; +% lua("print('>>>>>>>>>>>> boolean',mp.get.boolean('b'))") ; +% lua("print('>>>>>>>>>>>> boolean',mp.get.string('b'))") ; +% string s ; s := "TEST" ; +% lua("print('>>>>>>>>>>>> string',mp.get.number('s'))") ; +% lua("print('>>>>>>>>>>>> string',mp.get.boolean('s'))") ; +% lua("print('>>>>>>>>>>>> string',mp.get.string('s'))") ; +% \stopMPcode + +% \usemodule[graph] +% +% \startluacode +% local d = nil +% function MP.set(data) +% d = data +% end +% function MP.n() +% mp.print(d and #d or 0) +% end +% function MP.get(i,j) +% mp.print(d and d[i] and d[i][j] or 0) +% end +% \stopluacode +% +% \startluacode +% MP.set { +% { 1, 0.5, 2.5 }, +% { 2, 1.0, 3.5 }, +% } +% \stopluacode +% +% \startMPpage[instance=graph,offset=2mm] +% +% draw begingraph(3cm,5cm); +% numeric a[]; +% for j = 1 upto MP.n() : +% path b; +% augment.b(MP.get(j,1),MP.get(j,2)); +% augment.b(MP.get(j,1),MP.get(j,3)); +% setrange(0,0,3,4); +% gdraw b; +% endfor ; +% endgraph ; +% \stopMPpage + +% \starttext +% +% % \enabletrackers[metapost.variables] +% +% \startMPcode +% numeric n[] ; for i=1 upto 10: n[i] := 1/i ; endfor ; +% path p[] ; for i=1 upto 10: p[i] := fullcircle xyscaled (cm*i,cm/i) ; endfor ; +% numeric r[][] ; for i=1 upto 4 : for j=1 upto 3 : r[i][j] := uniformdeviate(1) ; endfor ; endfor ; +% pair u[][] ; for i=1 step 0.5 until 4 : for j=1 step 0.1 until 2 : u[i][j] := (i,j) ; endfor ; endfor ; +% +% passvariable("x",12345) ; +% passarrayvariable("n-array",n,1,7,1) ; +% passarrayvariable("p-array",p,1,7,1) ; +% passvariable("p",(1,1) .. (2,2)) ; +% +% startpassingvariable("b") +% for i=1 upto 4 : +% startpassingvariable(i) +% for j=1 upto 3 : +% passvariable(j,r[i][j]) +% endfor +% stoppassingvariable +% endfor +% stoppassingvariable ; +% +% startpassingvariable("a") +% startpassingvariable("test 1") +% passvariable(1,123) +% passvariable(2,456) +% stoppassingvariable ; +% startpassingvariable("test 2") +% passvariable(0,123) +% passvariable(1,456) +% passvariable(2,789) +% passvariable(999,987) +% stoppassingvariable ; +% startpassingvariable("test 3") +% passvariable("first",789) +% passvariable("second",987) +% stoppassingvariable +% stoppassingvariable ; +% +% startpassingvariable("c") +% for i=1 step 0.5 until 4 : +% startpassingvariable(i) +% for j=1 step 0.1 until 2 : +% passvariable(j,u[i][j]) +% endfor +% stoppassingvariable +% endfor +% stoppassingvariable ; +% +% draw fullcircle scaled 1cm ; +% \stopMPcode +% +% \ctxluacode{inspect(metapost.variables)} +% +% \ctxcommand{mprunvar("x")} + +\stoptext + + diff --git a/doc/context/sources/general/manuals/metafun/metafun-macros.tex b/doc/context/sources/general/manuals/metafun/metafun-macros.tex new file mode 100644 index 000000000..e1df13c92 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-macros.tex @@ -0,0 +1,91 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-macros + +\environment metafun-environment + +\startchapter[title={\METAFUN\ macros}] + +\index{metafun} + +\startintro + +\CONTEXT\ comes with a series of \METAPOST\ modules. In this chapter we will +summarize the most important \TEX\ and \METAPOST\ macros. More information can be +found in the documentation of the modules. + +\stopintro + +There are several ways to use the power of \METAFUN, either or not using +\CONTEXT. + +\startitemize[n] + +\startitem + You can create an independent \type {mp} file and process it with the + \METAPOST\ program or \MPTOPDF. Depending on what features you use, the + succes of a run depends on the proper set up of the programs that take care + of running \TEX\ for \type {btex}. +\stopitem + +\startitem + You can embed the graphic in a \type {\startMPpage} construct and process it + with \CONTEXT\ \MKIV. In that case you have the full \METAFUN\ functionality + available. If for some reason you still want to use \MKII, you need to use + \TEXEXEC\ as before processing the file, it will do a couple of checks on the + file. It will also make sure that the temporary files (\type {mpt} for \type + {textext}'s and \type {mpo} for outline fonts) are taken care of too. +\stopitem + +\startitem + You can integrate the graphic in the document flow, using buffers, \METAPOST\ + code sections, or (reusable) graphic containers. In that case the graphics + are processed runtime or between runs. This happens automatically. +\stopitem + +\stopitemize + +Unless you want to write low level \CONTEXT\ code yourself, there is no real +reason to look into the modules that deal with \METAPOST\ support. The +traditional (partly generic) code is collected in: + +\starttabulate[|lT|p|] +\NC supp-mps.tex \NC low level inclusion macros and housekeeping \NC\NR +\NC supp-mpe.tex \NC experimental extensions (like specials) \NC\NR +\NC supp-pdf.tex \NC \METAPOST\ to \PDF\ conversion \NC\NR +\stoptabulate + +Especially the last two can be used in other macro packages. However, in +\CONTEXT\ we have regrouped the code (plus more) in other files: + +\starttabulate[|lT|p|] +\NC meta-***.tex \NC definition and managing \NC\NR +\NC mlib-***.tex \NC processing and conversion \NC\NR +\stoptabulate + +The last category will certainly grow. Some of these modules are preloaded, +others can be loaded using the command \type {\useMPlibrary}, like + +\starttyping +\useMPlibrary[clp,txt] +\stoptyping + +for loading the predefined clipping paths and text tricks. + +The \METAPOST\ code is organized in files named \type {mp-****.mp}. The core file +is \type {mp-tool.mp} and this file can comfortably be used in stand||alone +graphics. The file \type {metafun.mp} is used to load the collection of modules +into a format. The collection of \METAPOST\ code files will grow in due time, but +as long as you use the \METAFUN\ format, you don't have to keep track of the +organization of files. Most files relate to subsystems and are loaded +automatically, like the files that implement page layout support and flow charts. + +Although this document is the main source of information, occasionally the source +code of \METAFUN, and in many cases the source code of \CONTEXT\ may contain +additional information and examples. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-positioning.tex b/doc/context/sources/general/manuals/metafun/metafun-positioning.tex new file mode 100644 index 000000000..5a3b1ece0 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-positioning.tex @@ -0,0 +1,1013 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-positioning + +\environment metafun-environment + +\startchapter[reference=sec:positioning,title={Positional graphics}] + +\startintro + +In this chapter, we will explore one of the more advanced, but also conceptually +more difficult, graphic capabilities of \CONTEXT. It took quite a few experiments +to find the {\em right} way to support these kind of graphics, and you can be +sure that in due time extensions will show up. You can skip this chapter if you +are no \CONTEXT\ user. Because we're now a decade into \MKIV\ the tricks here +will assume that you use \CONTEXT\ \MKIV\ because we have a more convenient +interface there. For old|-|school \MKII\ usage you can look in old \METAFUN\ +manuals or in the \type {mkii} source files. Of course we remain compatible, it's +just that more (convenient) interfaces were added. + +\stopintro + +\startsection[title={The status quo}] + +After \TEX\ has read a paragraph of text, it will try to break this paragraph +into lines. When this is done, the result is flushed and after that \TEX\ will +check if a page should be split off. As a result, we can hardly predict how a +document will come out. Therefore, when we want graphics to adapt themselves to +this text, maybe even to text broken across lines, we have to deal with this +asynchronous feature of \TEX\ in a rather advanced way. Before we present a way +of dealing with this complexity, we will elaborate on the nature of embedded +graphics in \TEX. + +When \TEX\ entered the world of typesetting, desktop printers were not that +common, let alone color desktop printers. But times have changed and nowadays we +want color and graphics and if possible we want them integrated in the text. When +\METAPOST\ showed up it depended on the \DVI\ processor to recognize the +\POSTSCRIPT\ code as being produced by \METAPOST\ and therefore also include the +fonts that were used. But color was still limited to \RGB. When \PDFTEX\ evolved +I wrote an interpreter (in \TEX) that could translate the output to \PDF. This +also opened up the possibility to add features to \METAPOST, like \CMYK\ colors, +shading, transparencies etc. But basically the \TEX\ and \METAPOST\ processes +were rather isolated. We could of course pass information to \METAPOST\ and pick +up information from \METAPOST\ in a second pass. That has changed in \LUATEX. + +In order to really integrate \METAPOST\ graphics into the flow you need to know +where you are on the page and how large graphics should be, especially when you +want them to depend on the layout. A first solution to this was to embed specials +in the \DVI\ that could later be used to extract positions. In retrospect this +was a relative trivial extension, something that could have been around much +earlier but somehow didn't happen. Anyhow, after some experiments \PDFTEX\ got a +native position tracker which meant that no post processor was needed. Of course +\LUATEX\ inherited this feature too. Because positioning is rather bound to the +macro package reading this chapter only makes sense when you use \CONTEXT. + +\stopsection + +\startbuffer[arrow:1] +\startMPpositionmethod{mypos:arrow} + \startMPpositiongraphic{mypos:arrow} + save pa, pb, pm, pab, na, nb, sa, sb ; + path pa, pb, pm, pab ; numeric na, nb ; string sa, sb ; + % the tags + sa := texstr("from") ; + sb := texstr("to") ; + % we need to check page crossing so we fetch the page numbers + na := positionpage(sa) ; + nb := positionpage(sb) ; + % we use the repositioned shapes + pa := positionbox(sa) ; + pb := positionbox(sb) ; + % but want circles instead of rectangles + pa := llcorner pa .. lrcorner pa .. urcorner pa .. ulcorner pa .. cycle ; + pb := llcorner pb .. lrcorner pb .. urcorner pb .. ulcorner pb .. cycle ; + pickup pencircle scaled 1pt ; + if na = nb : + % both are on the same page + fill pa withcolor .800white ; + fill pb withcolor .800white ; + draw pa withcolor .625yellow ; + draw pb withcolor .625yellow ; + pm := .5[center pa,center pb] shifted (0,2*LineHeight) ; + pab := center pa .. pm .. center pb ; + pab := pab cutbefore (pab intersectionpoint pa) ; + pab := pab cutafter (pab intersectionpoint pb) ; + drawarrow pab dashed evenly withcolor .625red ; + positionatanchor(sa) ; + elseif nb < na : + % they are on different pages and we're at the first one + fill pb withcolor .800white ; + draw pb withcolor .625yellow ; + pab := center pb {up} .. ulcorner bbox pb ; + pab := pab cutbefore (pab intersectionpoint pb) ; + drawarrow pab dashed evenly withcolor .625red ; + positionatanchor(sb) ; + else : + % they are on different pages and we're at the last one + fill pa withcolor .800white ; + draw pa withcolor .625yellow ; + pab := center pa {up} .. urcorner bbox pa ; + pab := pab cutbefore (pab intersectionpoint pa) ; + drawarrow pab dashed evenly withcolor .625red ; + positionatanchor(sa) ; + fi ; + \stopMPpositiongraphic + % we put it here at the first position + \MPpositiongraphic{mypos:arrow} + % we need to carry information forward and make sure that we also + % check and flush at the second position of the pair + \ifnum\MPp{\MPvar{from}}<\MPp{\MPvar{to}}\relax + \expanded{\setMPpositiongraphic{\MPvar{to}}{mypos:arrow}{to=\MPvar{from}}} + \fi +\stopMPpositionmethod +\stopbuffer + +\startbuffer[arrow:2] +\setMPpositiongraphic{A-1}{mypos:arrow}{to=A-2} +\stopbuffer + +\startbuffer[box:1] +\startMPpositiongraphic{mpos:box}{fillcolor,linecolor,linewidth} + string tag; tag := "\MPvar{self}" ; + path box ; box := positionbox(tag) ; + box := box enlarged \MPvar{filloffset} ; + fill box + withcolor \MPvar{fillcolor} ; + draw box + withcolor \MPvar{linecolor} + withpen pencircle scaled \MPvar{linewidth} ; + positioninregion ; +\stopMPpositiongraphic +\stopbuffer + +\startbuffer[box:1:also] +\startMPpositiongraphic{mpos:box}{fillcolor,linecolor,linewidth} + path box ; box := positionbox(texstr("self")) ; + box := box enlarged texvar("filloffset") ; + fill box + withcolor texvar("fillcolor") ; + draw box + withcolor texvar("linecolor") + withpen pencircle scaled texvar("linewidth") ; + positioninregion ; +\stopMPpositiongraphic +\stopbuffer + +\startbuffer[box:2] +\setupMPvariables + [mpos:box] + [linecolor=blue, + linewidth=\linewidth, + fillcolor=lightgray, + filloffset=2pt] + +\setupMPvariables[mpos:box][linecolor=darkred] +\setupMPvariables[mpos:par][linecolor=darkred] + +\startpositionoverlay{backgraphics} + \setMPpositiongraphic{A-0}{mpos:box}{self=A-0} + \setMPpositiongraphic{A-3}{mpos:box}{self=A-3} + \setMPpositiongraphic{A-4}{mpos:box}{self=A-4} +\stoppositionoverlay +\stopbuffer + +\getbuffer[arrow:1,arrow:2] +\getbuffer[box:1,box:2] + +\startsection[title={The concept}] + +\index {graphics+positioning} +\index {positioning} +\index {anchoring} + +Because we have a \LUA\ connection in \MPLIB, we have implemented a couple of +helpers that make live easier. This is also why the following examples are \MKIV\ +specific, although \MKII\ can do the same, but with a bit different set of +helpers. We can for instance query properties of \hpos {A-0} {positions} without +using \TEX\ macros but can use \METAPOST\ macros instead. Let's give an example. +The background and frame behind the word \type {position} in this paragraph is +not done with \type {\framed} but using a different mechanism: + +\starttyping +to get \hpos {A-0} {positions} sorted +\stoptyping + +The \type {\hpos} refers to a position and we have bound that position to a graphic: + +\starttyping +\setMPpositiongraphic{A-0}{mpos:box}{self=A-0} +\stoptyping + +The graphic itself is defined with: + +\typebuffer[box:1] + +A variant that has no macro calls and does all via the \LUA\ intercaface in \MKIV\ is +the following: + +\typebuffer[box:1:also] + +A \type {\hpos} position has several properties: the coordinates of the origin: +\type {x} and \type {y}, the dimensions of the boxed content, \type {w}, \type +{h} and \type {d}, and the page number \type {p}. An additional helper \type +{positioninregion} will move the drawing to the right spot in the region. +Examples or regions are the page, text area or some overlay. The \type +{positionatanchor} variant relocates to the anchor of the given tag. The first +helper is actually a shortcut for: + +\starttyping +currentpicture := currentpicture shifted - positionxy(positionanchor) ; +\stoptyping + +In our case we use a dedicated layer \type {backgraphics} that we have hooked into +the page backgrounds: + +\starttyping +\setupbackgrounds + [page] + [background={backgraphics,foreground,foregraphics}] + +\defineoverlay [backgraphics] [\positionoverlay{backgraphics}] +\defineoverlay [foregraphics] [\positionoverlay{foregraphics}] +\stoptyping + +The relation between position graphics and that layer are defined as follows +(we will come back to this in a moment): + +\typebuffer[box:2] + +\stopsection + +\startsection[title={A more detailed view}] + +As we know, a decent portion of \TEX's attention is focused on breaking +paragraphs into lines and determining the optimal point to split off the page. +Trying to locate the optimal points to break lines is a dynamic process. The +space between words is flexible and we don't know in advance when a \hpos {A-1} +{word} or piece of a word |<|maybe it's best to talk of typographic \hpos {A-2} +{globs} instead|>| will end up on the page. It might even cross the page +boundary. + +In the previous section we saw \hpos {A-3} {word} and \hpos {A-4} {globs} +encircled and connected by an arrow. This graphic can be drawn only when the +position and dimensions are known. Unfortunately, this information is only +available after the paragraph is typeset and the best breakpoints are chosen. +\bpos {A-5} Because the text must be laid on top of the graphic, the graphic must +precede the first word in the typeset stream or it must be positioned on a +separate layer. In the latter case it can be calculated directly after the +paragraph is typeset, but in the former case a second pass is needed. \epos {A-5} +Because such graphics are not bound to one paragraph, the multi||pass option +suits better because it gives us more control: the more we know about he final +state, the better we can act upon it. Think of graphics on the first page that +depend on the content of the last page \bpos {A-6} or, as in this paragraph, +backgrounds that depend on the typeset text. \epos {A-6} + +The arrows that connect the shapes are drawn with the following code that now +looks familiar: + +\typebuffer[arrow:1] + +and + +\typebuffer[arrow:2] + +However, here we anchor at one of the positions because we don't flush in a layer +but at the position itself. Indeed it looks complex. + +It may be clear now that we need some positional information in order to provide +features like the ones shown here. The fact that we will act upon in a second +pass simplifies the task, although it forces us to store the positional +information between runs in some place. This may look uncomfortable at first +sight, but it also enables us to store some additional information. Now why is +that needed? + +A position has no dimensions, it's just a place somewhere on the page. In order +to do tricks like those shown here, we also need to know the height and depth of +lines at a specific point as well as the width of the box(es) we're dealing with. +In the encircled examples, the dimensions of the box following the positional +node are stored along with the position. + +In order to process the graphics, we tag each point with a name, so that we can +attach actions to those points. In fact they become trigger points. As we will +demonstrate, we also need to store the current page number. This brings the data +stored with a point to: + +\starttyping +<identifier> <pagenumber> <x> <y> <width> <height> <depth> +\stoptyping + +Actually we store more information, for example the region in which the positions +sit. Depending on the use we can also get access to paragraph and line properties +but discussing these is beyond this manual. These are for instance used in the +text backgrounds. + +The page number is needed in order to let the graphics engine determine boundary +conditions. Backgrounds like those shown here can span multiple pages. In order +to calculate the right backgrounds, some additional information must be +available, like the top and bottom of the current text area. In fact, these are +just normal points that can be saved while processing the split off page. So, +apart from positioning anchors in the text we need anchors on crucial points of +the layout. This means that this kind of support cannot be fully integrated into +the \TEX\ kernel, unless we also add extensive support for layout definitions, +and that is probably not what we want. + +As soon as something like $(x,y)$ shows up, a logical question is where $(0,0)$ +is located. Although this is a valid question, the answer is less important than +you may expect. Even if we know that ($0,0)$ is \quote {officially} located in +the bottom left corner of the page, the simple fact that in \CONTEXT\ we are +dealing with a mixed page concept, like paper size and print paper size, or left +and right pages, forces us to think in relative positions instead of absolute +ones. Therefore, graphics, even those that involve multiple positions, are +anchored to a position on the layer on which they are located. + +Users who simply want to use these features may wonder why we go into so much +detail. The main reason is that in the end many users will want to go beyond the +simple cases, and when dealing with these issues, you must be aware not only of +height, depth and width, but also of the crossing of a page boundary, and the +height and depth of lines. In some cases your graphics may have to respond to +layout characteristics, like differences between odd and even pages. Given that +unique identifiers are used for anchor points, in \CONTEXT\ you can have access +to all the information needed. Here are some of the helpers: + +\starttabulate[|T||] +\NC positionpath (tag) \NC the path determined by width, height and depth \NC \NR +\NC positionxy (tag) \NC the origin \NC \NR +\NC positionwhd (tag) \NC the dimensions (in a triplet) \NC \NR +\NC positionpage (tag) \NC the page number fo the position \NC \NR +\NC positionregion(tag) \NC the region that the position sits in \NC \NR +\NC positionbox (tag) \NC the positioned box (path shifted over coordinates) \NC \NR +\NC positionanchor \NC the current anchor of the region \NC \NR +\stoptabulate + +The \type {positionwhd} macro returns a triplet that you can query, like: + +\starttyping +triplet whd ; whd := positionwhd("\MPvar{from}"); +numeric wd; wd := wdpart whd ; +\stoptyping + +We will add more such convenient helpers in the future. In the \CONTEXT\ +distribution you can find examples (in manuals or librarties) that demonstrate +other tricks with positioning. + +\stopsection + +\startsection[title={Anchors and layers}] + +\index{anchoring} +\index{layers} + +\startbuffer[g-circle] +\startMPpositiongraphic{mypos:circle} + path p ; p := positionbox(texstr("self")) ; + p := fullcircle xsized (bbwidth(p)+4pt) shifted center p ; + pickup pencircle scaled 1pt ; + fill p withcolor .800white ; + draw p withcolor .625yellow ; + positioninregion ; +\stopMPpositiongraphic +\stopbuffer + +\startbuffer[g-line] +\startMPpositiongraphic{mypos:line} + path pa, pb, pab ; numeric na, nb ; string ta, tb ; + ta := texstr("from") ; + tb := texstr("to") ; + na := positionpage(ta) ; + nb := positionpage(tb) ; + pa := positionbox(ta) ; + pb := positionbox(tb) ; + pa := fullcircle xsized (bbwidth(pa)+4pt) shifted center pa ; + pb := fullcircle xsized (bbwidth(pb)+4pt) shifted center pb ; + if na = nb : + pab := center pa -- center pb ; + pab := pab cutbefore (pab intersectionpoint pa) ; + pab := pab cutafter (pab intersectionpoint pb) ; + pickup pencircle scaled 1pt ; + draw pab withcolor .625yellow ; + positioninregion ; + fi ; +\stopMPpositiongraphic +\stopbuffer + +\getbuffer[g-circle,g-line] + +\startbuffer[a] +\setMPpositiongraphic{X-1}{mypos:arrow}{to=X-2} +\setMPpositiongraphic{X-2}{mypos:arrow}{to=X-3} +\stopbuffer + +\startbuffer[b] +In a previous section we saw that some \hpos {X-1} {words} were +\hpos {X-2} {circled} and connected by an \hpos {X-3} {arrow}. +As with most things in \CONTEXT, marking these words is separated +from declaring what to do with those words. This paragraph is keyed +in as: +\stopbuffer + +\getbuffer[a,b] + +\typebuffer[b] + +We see three position anchors, each marked by an identifier: \type {X-1}, \type +{X-2} and \type {X-3}. Each of these anchors can be associated with a (series) of +graphic operations. Here we defined: + +\typebuffer[a] + +These examples clearly demonstrate that we cannot control to what extent graphics +will cover text and vice versa. A solution to this problem is using position +overlays. We can define such an overlay as follows: + +\startbuffer +\startpositionoverlay{backgraphics} + \setMPpositiongraphic{G-1}{mypos:circle} + \setMPpositiongraphic{G-2}{mypos:circle} + \setMPpositiongraphic{G-3}{mypos:circle} + \setMPpositiongraphic{G-4}{mypos:circle} +\stoppositionoverlay + +\startpositionoverlay{foregraphics} + \setMPpositiongraphic{G-1}{mypos:line}{to=G-2} + \setMPpositiongraphic{G-2}{mypos:line}{to=G-3} + \setMPpositiongraphic{G-3}{mypos:line}{to=G-4} +\stoppositionoverlay +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +First we have defined an \hpos {G-1} {\strut overlay}. This +overlay can be attached to some overlay layer, like, in our +case, the \hpos {G-2} {\strut page}. We define four small \hpos +{G-3} {\strut circles}. These are drawn as soon as the page +overlay is typeset. Because they are located in the +background, they don't cover the \hpos {G-4} {\strut text}, while +the lines do. The previous paragraph was typeset by saying: +\stopbuffer + +\getbuffer \typebuffer + +As said, the circles are on the background layer, but the lines are not! They are +positioned on top of the text. This is a direct result of the definition of the +page background: + +\starttyping +\defineoverlay [foregraphics] [\positionoverlay{foregraphics}] +\defineoverlay [backgraphics] [\positionoverlay{backgraphics}] + +\setupbackgrounds + [page] + [background={backgraphics,foreground,foregraphics}] +\stoptyping + +\doifmode{screen}{\writestatus{CHECK}{POSITION GRAPHICS}} + +In this definition, the predefined overlay \type {foreground} inserts the page +data itself, so the foreground graphics end up on top. This example also +demonstrates that you should be well aware of the way \CONTEXT\ builds a page. +There are six main layers, in some cases with sublayers. The body text goes into +the main text layer, which, unless forced otherwise, lays on top. + +\startitemize[packed,n,columns,three] +\item paper background +\item area backgrounds +\item page backgrounds +\item text areas +\item logo areas +\item main text +\stopitemize + +The paper background is used for special (sometimes internal) purposes. There are +three page backgrounds: left, right and both. The text areas, logo areas and +backgrounds form a $5 \times 5$ matrix with columns containing the leftedge, +leftmargin, text, rightmargin, and rightedge. The rows of the matrix contain the +top, header, text, footer, and bottom. The main text is what you are reading now. + +Since the page background is applied last, the previous layers can be considered +to be the foreground to the page background layer. And, indeed, it is available +as an overlay under the name \type {foreground}, as we already saw in the +example. Foregrounds are available in most cases, but (for the moment) not when +we are dealing with the text area. Since anchoring the graphics is implemented +rather independent of the position of the graphics themselves, this is no real +problem, we can put them all on the page layer, if needed in separate overlays. + +How is such a graphic defined? In fact these graphics are a special case of the +already present mechanism of including \METAPOST\ graphics. The circles are +defined as follows: + +\typebuffer[g-circle] + +Drawing the lines is handled in a similar fashion. + +\typebuffer[g-line] + +The command \tex {startMPpositiongraphic} defines a graphic, in this example we +have called it \type {mypos:circle}. Here we show the definition out of order but +normally you need to define it before you refer to it. + +The \METAPOST\ macro \type {positionbox} returns a box that is constructed from +the coordinates and dimensions. After this call, the corners are available via +\type {llcorner}, \type {lrcorner}, \type {urcorner} and \type {ulcorner}. The +center is accessible by \type {center}. When we are finished drawing the graphic, +we can anchor the result with \type {positioninregion}. This macro automatically +handles positioning on specific layers. The helper macros are not loaded by +default, you do that with: + +\typebuffer[g-include] + +The position macro \type {\MPpos} returns the current characteristics of a +position. The previously defined G~positions return: + +\starttabulate[|c|c|c|c|c|c|c|] +\HL +\NC position\NC page\NC$x$\NC$y$\NC width\NC height\NC depth\NC\NR +\HL +\NC G-1\NC\MPp{G-1}\NC\MPx{G-1}\NC\MPy{G-1}\NC\MPw{G-1}\NC\MPh{G-1}\NC\MPd{G-1}\NC\NR +\NC G-2\NC\MPp{G-2}\NC\MPx{G-2}\NC\MPy{G-2}\NC\MPw{G-2}\NC\MPh{G-2}\NC\MPd{G-2}\NC\NR +\NC G-3\NC\MPp{G-3}\NC\MPx{G-3}\NC\MPy{G-3}\NC\MPw{G-3}\NC\MPh{G-3}\NC\MPd{G-3}\NC\NR +\NC G-4\NC\MPp{G-4}\NC\MPx{G-4}\NC\MPy{G-4}\NC\MPw{G-4}\NC\MPh{G-4}\NC\MPd{G-4}\NC\NR +\HL +\stoptabulate + +The numbers represent the real pagenumber~$p$, the current position $(x,y)$, and +the dimensions of the box $(w,h,d)$ if known. These values are fed directly into +\METAPOST\ graphics but the individual components can be asked for by \type +{\MPp}, \type {\MPx}, \type {\MPy}, \type {\MPw}, \type {\MPh} and \type {\MPd}. + +In the previous definition of the graphic, we saw another macro, \type {\MPvar}. +When we invoke a graphic or attach a graphic to a layer, we can pass variables. +We can also set specific variables in other ways, as we will see later. + +\starttyping +\setMPpositiongraphic{G-1}{mypos:circle} +\setMPpositiongraphic{G-1}{mypos:line}{to=G-2} +\stoptyping + +In the second definition, we let the variable \type {to} point to another +position. When needed, we can ask for the value of \type {to} by \type +{\MPvar{to}}. For reasons of convenience, the current position is assigned +automatically to \type {from} and \type {self}. This means that in the line we +saw in the graphic: + +\starttyping +path p ; p := positionbox(texstr("self")) ; +\stoptyping + +\type {texstr("self")} will return the current position, which, fed to \type +{positionbox} will return a box with the right dimensions. We already warned the +reader: this is not an easy chapter. + +\stopsection + +\startsection[title={More layers}] + +\index{layers} + +\setupbackgrounds + [state=repeat] + +Overlays are one of the nicer features of \CONTEXT\ and even more nice things can +be build on top of them. Overlays are defined first and then assigned to framed +boxes using the \type {background} variable. + +You can stack overlays, which is why they are called as such. You can use the +special overlay called \type {foreground} to move the topmost (often text) layer +down in the stack. + +\starttabulate +\HL +\NC background overlay \NC a text, graphic, hyperlink or widget \NC \NR +\NC position overlay \NC a series of macros triggered by positions \NC \NR +\NC background layer \NC a box that can hold boxes with offsets \NC \NR +\HL +\stoptabulate + +The last kind of layer can be used in other situations as well, but in most cases +it will be hooked into a background overlay. + +\startbuffer +\definelayer[MyLayer][option=test] + +\setupbackgrounds[text][leftmargin][background=MyLayer] + +\setlayer[MyLayer][x=.5cm,y=5cm] + {\rotate{\framed{This goes to the background}}} +\stopbuffer + +\typebuffer \getbuffer \setuplayer[MyLayer][option=] % no frames + +In this case the framed text will be placed in the background of the (current) +page with the given offset to the topleft corner. Instead of a fixed position, +you can inherit the current position using the \type {position} directive. Say +that we have a layer called \type {YourLayer} which we put in the background of +the text area. + +\startbuffer +\definelayer[YourLayer] +\setupbackgrounds[text][text][background=YourLayer] +\stopbuffer + +\typebuffer \getbuffer + +We can now move some framed text to this layer using \type {\setlayer} with the +directive \type {position} set to \type {yes}. + +\startbuffer +here: \setlayer[YourLayer][position=yes]{\inframed{Here}} +\stopbuffer + +\typebuffer + +You can influence the placement by explicitly providing an offset (\type +{hoffset} and|/|or \type {voffset}), a position (\type {x} and|/|or \type {y}) or +a location directive (\type {location}). Normally you will use the offsets for +the layer as a whole and the positions for individual contributions. The next +example demonstrates the use of a location directive. + +\startbuffer +here: \setlayer[YourLayer][position=yes,location=c]{\inframed{Here}} +\stopbuffer + +\typebuffer \getbuffer + +Many layers can be in use at the same time. In the next example we put something +in the page layer. By default, we turn on position tracking, which visualizes the +bounding box of the content and shows the reference point. + +\startbuffer +\definelayer[BackLayer][position=yes] +\setupbackgrounds[page][background=BackLayer] +\stopbuffer + +\typebuffer \getbuffer + +\setupbackgrounds + [page] + [background={PageFrame,BackLayer,backgraphics,foreground,foregraphics}] + +Next we define an overlay that we can put behind for instance framed texts. We +use \METAPOST\ to draw \type {Shape}. + +\startbuffer +\defineoverlay[Shape] [BackLayer] [\uniqueMPgraphic{Shape}] + +\startuniqueMPgraphic{Shape} + path p ; p := fullcircle xyscaled(OverlayWidth,OverlayHeight) ; + fill p withcolor \MPcolor{lightgray} ; + draw p withpen pencircle scaled 1pt withcolor \MPcolor{darkred} ; +\stopuniqueMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer[def] +\defineframed[Shaped][background=Shape,frame=off,location=low] +\stopbuffer + +\getbuffer[def] + +We can now put this background shape behind the running text, for instance with: + +\startbuffer +.... some \inframed[background=Shape]{text} with a frame ... +.... some \Shaped{text} with a frame ... +\stopbuffer + +\typebuffer + +\startlines +\getbuffer +\stoplines + +The \type {\Shaped} macro was defined as: + +\typebuffer[def] + +Watch how the graphics are moved to the background while the frame of the first +text stays on top, since it remains part of the text flow. + +\startbuffer[def] +\setuplayer[BackLayer][direction=reverse] +\stopbuffer + +\getbuffer[def] + +\startlines +\getbuffer +\stoplines + +In the previous instance of the example we have reversed the stacking. Reversal +can be done with the \type {direction} directive. + +\typebuffer[def] + +% next series + +\startbuffer +\setuplayer + [BackLayer] + [position=no,corner=bottom,height=\paperheight] + +\setlayer[BackLayer][x=2cm,y=10cm,location=bl] + {\externalfigure[somecow.pdf][width=1cm]} + +\setlayer[BackLayer][x=1cm,y=8cm,location=br] + {\externalfigure[somecow.pdf][width=1cm]} + +\setlayer[BackLayer][x=2cm,y=4cm,location=tl] + {\externalfigure[somecow.pdf][width=1cm]} + +\setlayer[BackLayer][x=10cm,y=1cm,location=tr] + {\externalfigure[somecow.pdf][width=1cm]} +\stopbuffer + +You can influence the placement of a background component by using a different +anchor point. + +\typebuffer {\setuplayer[option=test]\getbuffer} + +\startbuffer[xx] +\setuplayer + [BackLayer] + [position=no,corner=bottom,height=\paperheight] + +\setlayer[BackLayer][x=15cm,y=5cm,location=bl] + {\externalfigure[somecow.pdf][width=3cm]} + +\setlayer[BackLayer][x=15cm,y=5cm,location=br] + {\externalfigure[somecow.pdf][width=3cm]} + +\setlayer[BackLayer][x=15cm,y=5cm,location=tl] + {\externalfigure[somecow.pdf][width=2cm]} + +\setlayer[BackLayer][x=15cm,y=5cm,location=tr] + {\externalfigure[somecow.pdf][width=2cm]} + +\setlayer[BackLayer][x=15cm,y=5cm,location=c] + {\externalfigure[somecow.pdf][width=3cm]} +\stopbuffer + +% \startpostponing + +Instead of using relative positions, you can also use absolute ones. Of course +you need to know how your coordinates relate to the rest of the layout +definition. + +\typebuffer[xx] + +These examples again demonstrate how we can influence the placement by assigning +an anchor point to \type {position}. Here we also put the reference point in the +lower left corner (\type {bottom}). This mechanism only works when we also use +\type {height}. + +{\setuplayer[option=test]\getbuffer[xx]} + +\page + +% \stoppostponing + +\setupbackgrounds + [page] + [background={PageFrame,DemoLayer,backgraphics,foreground,foregraphics}] + +\definelayer + [DemoLayer] + [position=yes] + +\startbuffer +\definelayer + [DemoLayer] + [position=yes] + +\startplacefigure[title={Demo 1}] + \ruledhbox\bgroup + \setlayerframed + [DemoLayer] [hoffset=-10mm,voffset=5mm] + {\startMPcode + fill fullcircle scaled 2cm withcolor .625red ; + \stopMPcode}% + \setlayerframed + [DemoLayer] [voffset=-10mm] + {\startMPcode + fill fullcircle scaled 2cm withcolor .625green ; + \stopMPcode}% + \setlayerframed + [DemoLayer] [hoffset=10mm,voffset=5mm] + {\startMPcode + fill fullcircle scaled 2cm withcolor .625blue ; + \stopMPcode}% + \egroup +\stopplacefigure +\stopbuffer + +\getbuffer + +One of the reasons for developing the layer mechanism was that we needed to +slightly change the position of figures in the final stage of typesetting. The +previous pages demonstrate how one can position anything anywhere on the page, +but in the case of figures the position may depend on where the text ends up on +the page. + +Normally, when you manipulate a document this way, you are in the final stage of +typesetting. You may qualify this as desk top publishing without actually using a +desktop. + +\typebuffer + +\startbuffer[demo] +\startbuffer +\setlayer [DemoLayer] + [position=yes, + voffset=-1.5cm, + width=3cm, + height=2cm] + {\MPfigure{somecow.pdf}{scaled .5 slanted .5}} +\stopbuffer + +\placefigure[right]{}{\ruledhbox{\getbuffer}} +\stopbuffer + +{\setuplayer[option=test]\getbuffer[demo]} + +The previous example also demonstrated the use of \METAPOST\ for rotating the +picture. The \type {\MPfigure} macro encapsulates the code in a shortcut. You can +achieve special effects by using the layers behind floating bodies and alike, but +always keep in mind that the readability of the text should not be violated too +much. + +\typebuffer[demo] + +In these examples we added a \type {\ruledhbox} around the pseudo graphics so +that you can see what the size is of those graphics. + +% summary + +We have already seen a lot of parameters that can be used to control the content +of a layer. There are a few more. General housekeeping takes place with: + +\starttabulate[|Tl|Tl|l|] +\HL +\NC state \NC start \NC enable the layer \NC \NR +\NC \NC stop \NC disable the layer \NC \NR +\NC position \NC no \NC use absolute positions \NC \NR +\NC \NC yes \NC use relative positions \NC \NR +\NC \NC overlay \NC idem, but ignore the size \NC \NR +\NC direction \NC normal \NC put new data on top \NC \NR +\NC \NC reverse \NC put new data below old data \NC \NR +\HL +\stoptabulate + +Sometimes all data needs to be offset in a similar way. You can use both offset +parameters for that. + +\starttabulate[|Tl|l|] +\HL +\NC hoffset \NC an additional horizontal displacement \NC \NR +\NC voffset \NC an additional vertical displacement \NC \NR +\HL +\stoptabulate + +You can position data anywhere in the layer. When positioning is turned on, the +current position will get a placeholder. You can change the dimensions of that +placeholder (when \type {position} is set to \type {overlay}), zero dimensions +are used. + +\starttabulate[|Tl|l|] +\HL +\NC x \NC the horizontal displacement \NC \NR +\NC y \NC the vertical displacement \NC \NR +\NC width \NC the (non natural) width \NC \NR +\NC height \NC the (non natural) height \NC \NR +\NC location \NC \tttf l r t b c lt lb rt rb \NC \NR +\HL +\stoptabulate + +The \type {location} directive determines what point of the data is used as +reference point. You can keep track of this point and the placement when you +enable test mode. This is how the rectangles in the previous examples were +drawn. + +\starttabulate[|Tl|Tl|l|] +\HL +\NC option \NC test \NC show positioning information \NC \NR +\HL +\stoptabulate + +When you are enhancing the final version of a document, you can explicitly +specify on what page the data will go. Use this option with care. + +\starttabulate[|Tl|l|] +\HL +\NC page \NC the page where the data will go \NC \NR +\HL +\stoptabulate + +Because layers can migrate to other pages, they may disappear due to the +background not being recalculated. In case of doubt, you can force repetitive +background calculation by: + +\starttyping +\setupbackgrounds[state=repeat] +\stoptyping + +% restore 'm + +\setupbackgrounds + [page] + [background={PageFrame,backgraphics,foreground,foregraphics}] + +\setupbackgrounds + [state=start] + +\stopsection + +\startsection[title={Complex text in graphics}] + +\index{text} + +If you like to embed \METAPOST\ snippets in \CONTEXT, you may want to combine +text and graphics and let \METAPOST\ provide the position and the dimensions of +the text to be typeset outside by \TEX. For most applications using the \METAFUN\ +\type {textext} macro works well enough, but when the typeset text needs to +communicate with the typesetting engine, for instance because it contains +hyperlinks or references, you can use the following method: + +\startitemize[packed] +\item define a layer +\item define a (reusable) graphic +\item put your text into the layer +\item combine the graphic with the text +\stopitemize + +You must be aware of the fact that when the layer is flushed, its content is +gone. You can take advantage of this by using the same graphic with multiple +texts. + +\startbuffer +\definelayer[test] +\stopbuffer + +\typebuffer \getbuffer + +You don't need to pass the width and height explicitly, but when you do so, you +have access to them later. + +\startbuffer +\startuseMPgraphic{oeps} + path p ; p := fullcircle scaled 6cm ; + fill p withcolor .8white ; + draw p withpen pencircle scaled 1mm withcolor .625red ; + register ("somepos-1",0cm,0cm,center currentpicture) ; + register ("somepos-2",3cm,1cm,(-1cm,-1cm)) ; + register ("somepos-3",2cm,0cm,(-2cm,2cm)) ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +The \METAFUN\ \type {register} macro takes the following arguments: + +\starttyping +register ("tag",width,height,(x offset,y offset)) ; +\stoptyping + +The width and height are available in the macros \type {\MPlayerwidth} and \type +{\MPlayerheight} and are equivalent to \type {\MPw{tag}} and \type {\MPh{tag}}, + +\startbuffer +\setMPlayer [test] [somepos-1] [location=c] + {Does it work al right?} + +\setMPlayer [test] [somepos-2] + {\framed + [width=\MPlayerwidth,height=\MPlayerheight, + background=color,backgroundcolor=white] + {It Works!}} + +\setMPlayer [test] [somepos-3] + {\externalfigure[cow-fun.mps][width=2cm]} +\stopbuffer + +\typebuffer \getbuffer + +Combining the graphic and the text is handled by the macro \type {\getMPlayer}. + +\startbuffer +\getMPlayer [test] {\useMPgraphic{oeps}} +\stopbuffer + +\typebuffer \getbuffer + +The macro \type {\getMPlayer} is built on top of \type {\framed}. The settings +passed in the (optional) second argument are the same as those to \type +{\framed}. + +\starttyping +\getMPlayer + [test] + [frame=on,offset=5pt] + {\useMPgraphic{oeps}} +\stoptyping + +As you see, you need a bit of a twisted mind to handle graphics this way, but at +least the functionality is there to create complex graphics in a declarative way. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-reference.tex b/doc/context/sources/general/manuals/metafun/metafun-reference.tex new file mode 100644 index 000000000..6eb177949 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-reference.tex @@ -0,0 +1,659 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-reference + +\environment metafun-environment + +\startchapter[reference=reference,title={Reference}] + +\startintro + +In this chapter, we will demonstrate most of the drawing related primitives and +macros as present in plain \METAPOST\ and \METAFUN\ extensions. + +If a path is shown and|/|or a transformation is applied, we show the original in +red and the transformed path or point in yellow. The small dark gray crosshair is +the origin and the black rectangle the bounding box. In some drawings, in light +gray we show the points that make up the path. + +This list describes traditional \METAPOST\ and the stable part of \METAFUN. As +\METAPOST\ evolves, new primitives are added but they are not always that +relevant to us. If you browse the \METAFUN\ sources you will for sure notice more +functionality than summarized here. Most of that is meant for usage in \CONTEXT\ +and not exposed to the user. Other macros are still somewhat experimental but +might become more official at some point. The same is true for \METAFUN\ +commands: not all make sense for daily usage and some are just there as helper +for additional modules. + +\stopintro + +\startsection[title={Paths}] + +\index{paths} + +\ShowSampleA {mc} {pair} {(1,.5)} +\ShowSampleA {mm} {pair .. pair} {(0,0)..(.75,0)..(1,.25)..(1,1)} +\ShowSampleA {mm} {pair ... pair} {(0,0)..(.75,0)...(1,.25)..(1,1)} +\ShowSampleA {mm} {pair -- pair\quad (a)} {(0,0)--(.75,0)--(1,.25)--(1,1)} +\ShowSampleA {mm} {pair -- pair\quad (b)} {(0,0)..(.75,0)--(1,.25)..(1,1)} +\ShowSampleA {mm} {pair --- pair} {(0,0)..(.75,0)---(1,.25)..(1,1)} + +\ShowSampleA {mm} {pair softjoin pair} {(0,0)..(.75,0) softjoin (1,.25)..(1,1)} +\ShowSampleA {mp} {controls pair} {(0,0)..controls (.75,0)..(1,1)} +\ShowSampleA {mp} {controls pair and pair} {(0,0)..controls (.75,0) and (1,.25)..(1,1)} +\ShowSampleA {mp} {tension numeric} {(0,0)..(.75,0)..tension 2.5..(1,.25)..(1,1)} +\ShowSampleA {mp} {tension num.. and num..} {(0,0)..(.75,0)..tension 2.5 and 1.5..(1,.25)..(1,1)} +\ShowSampleA {mp} {tension atleast numeric} {(0,0)..(.75,0)..tension atleast 1..(1,.25)..(1,1)} + +\ShowSampleA {mp} {cycle} {(0,0)--(1,0)--(1,1)--cycle} +\ShowSampleA {mp} {curl numeric} {(0,0){curl 1}..(.75,0)..(1,.25)..(1,1)} +\ShowSampleA {mp} {dir numeric} {(0,0){dir 30}..(1,1)} +\ShowSampleA {mm} {left} {(0,0){left}..(1,1)} +\ShowSampleA {mm} {right} {(0,0){right}..(1,1)} +\ShowSampleA {mm} {up} {(0,0){up}..(1,1)} +\ShowSampleA {mm} {down} {(0,0){down}..(1,1)} + +\ShowSampleA {mp} {path \& path} {(0,0)..(.75,.25) \& (.75,.25)..(1,1)} + +\ShowSampleA {mv} {unitvector} {origin--unitvector(1,1)} +\ShowSampleA {mp} {dir} {origin--dir(45)} +\ShowSampleA {mp} {angle} {origin--dir(angle(1,1))} + +\ShowSampleA {mv} {fullcircle} {fullcircle} +\ShowSampleA {fv} {unitcircle} {unitcircle} +\ShowSampleA {fv} {fullsquare} {fullsquare} +\ShowSampleA {mv} {unitsquare} {unitsquare} +\ShowSampleA {fv} {fulltriangle}{fulltriangle} +\ShowSampleA {fv} {unittriangle}{unittriangle} +\ShowSampleA {fv} {fulldiamond} {fulldiamond} +\ShowSampleA {fv} {unitdiamond} {unitdiamond} + +\ShowSampleA {mv} {halfcircle} {halfcircle} +\ShowSampleA {mv} {quartercircle} {quartercircle} + +\ShowSampleA {fv} {llcircle} {llcircle} +\ShowSampleA {fv} {lrcircle} {lrcircle} +\ShowSampleA {fv} {urcircle} {urcircle} +\ShowSampleA {fv} {ulcircle} {ulcircle} +\ShowSampleA {fv} {tcircle} {tcircle} +\ShowSampleA {fv} {bcircle} {bcircle} +\ShowSampleA {fv} {lcircle} {lcircle} +\ShowSampleA {fv} {rcircle} {rcircle} + +\ShowSampleA {fv} {triangle} {triangle} +\ShowSampleA {fv} {righttriangle} {righttriangle} +\ShowSampleA {fv} {uptriangle} {uptriangle} +\ShowSampleA {fv} {lefttriangle} {lefttriangle} +\ShowSampleA {fv} {downtriangle} {downtriangle} + +\ShowSampleA {fv} {lltriangle} {lltriangle} +\ShowSampleA {fv} {lrtriangle} {lrtriangle} +\ShowSampleA {fv} {urtriangle} {urtriangle} +\ShowSampleA {fv} {ultriangle} {ultriangle} + +\ShowSampleA {mm} {flex(pair,pair,pair)} + {flex ((0,0),(1,1),(1,0))} +\ShowSampleA {mm} {superellipse(pair,p..,p..,p..,num..)} + {superellipse((1,.5),(.5,1),(0,.5),(.5,0),.75)} + +\ShowSampleA {fm} {path smoothed numeric/pair} {unitsquare scaled 1.5 smoothed .2} +\ShowSampleA {fm} {path cornered numeric/pair} {lltriangle scaled 1.5 cornered .2} +\ShowSampleA {fm} {path superellipsed numeric} {unitsquare scaled 1.5 superellipsed .75} +\ShowSampleA {fm} {path randomized numeric/pair} {unitsquare scaled 1.5 randomized (.2,.2)} +\ShowSampleA {fm} {path randomizedcontrols numeric/pair} {fullcircle scaled 1.5 randomizedcontrols (.2,.2)} +\ShowSampleA {fm} {path squeezed numeric/pair} {unitsquare scaled 1.5 squeezed (.2,.1)} +\ShowSampleA {fm} {path snapped numeric/pair} {fullcircle scaled 1.5 snapped (.2,.1)} + +\ShowSampleB {fm} {punked path} + {unitcircle scaled 1.5} + {punked unitcircle scaled 1.5} + +\ShowSampleB {fm} {curved path} + {((0,0)--(.2,1)--(1,.2)--cycle)} + {curved ((0,0)--(.2,1)--(1,.2)--cycle)} + +\ShowSampleB {fm} {laddered path} + {((0,0)--(1.4,.8)--(2.8,1.2)--(6.2,1.6))} + {laddered ((0,0)--(1.4,.8)--(2.8,1.2)--(6.2,1.6))} + +\ShowSampleB {fm} {path paralleled distance} + {((0,0)--(5,1))} + {((0,0)--(5,1)) paralleled .25} + +\ShowSampleB {fm} {shortened path} + {((0,0)--(6,1))} + {((0,0)--(6,1)) shortened 1} + +\ShowSampleB {fm} {unspiked path} + {((0,0)--(1,0)--(1,1)--(2,1)--(1,1)--(0,1)) shifted (-3,0)} + {unspiked ((0,0)--(1,0)--(1,1)--(2,1)--(1,1)--(0,1))} + +\ShowSampleB {fm} {simplified path} + {((0,0)--(1,0)--(2,0)--(2,1)--(0,1)--cycle) shifted (-3,0)} + {simplified ((0,0)--(1,0)--(2,0)--(2,1)--(0,1)--cycle)} + +\ShowSampleB {fm} {path blownup numeric/pair} + {fullcircle scaled 1.5} + {(fullcircle scaled 1.5) blownup .1} + +\ShowSampleB {fm} {path stretched numeric/pair\quad (a)} + {fullcircle scaled 1.5} + {(fullcircle scaled 1.5) stretched (1.1,0.8)} + +\ShowSampleB {fm} {path stretched numeric\quad (b)} + {((0,0)--(1,1))} + {((0,0)--(1,1)) stretched 1.5} + +\ShowSampleB {fm} {path xstretched numeric} + {fullcircle} + {fullcircle xstretched 5} + +\ShowSampleB {fm} {path ystretched numeric} + {fullcircle} + {fullcircle ystretched 1.5} + +\ShowSampleB {fm} {path enlonged numeric} + {((0,0)--(1,1))} + {((0,0)--(1,1)) enlonged 1.5} + +\ShowSampleB {fm} {path shorted numeric} + {((0,0)--(2,2))} + {((0,0)--(2,2)) shortened 0.5} + +\ShowSampleA {fm} {roundedsquare(num..,num..,num..)} + {roundedsquare(2,1,.2)} + +\ShowSampleA {fm} {tensecircle(num..,num..,num..)} + {tensecircle(2,1,.2)} + +\ShowSampleA {fm} {pair crossed size} + {origin crossed 1} + +\ShowSampleA {fm} {path crossed size} + {fullcircle scaled 2 crossed .5} + +\ShowSampleA {fm} {(constructed)function} + {constructedfunction("--")("x","sin(x)",0,2pi,pi/10)} + +\ShowSampleA {fm} {curvedfunction} + {curvedfunction("x","sin(x)",0,2pi,pi/10)} + +\ShowSampleA {fm} {straightfunction} + {straightfunction("x","sin(x)",0,2pi,pi/10)} + +\ShowSampleA {fm} {constructedpath} + {constructedpath("..")((0,0),(1,2),(2,1),(3,2))} + +\ShowSampleA {fm} {curvedpath} + {curvedpath((0,0),(1,2),(2,1),(3,2))} + +\ShowSampleA {fm} {straightpath} + {straightpath((0,0),(1,2),(2,1),(3,2))} + +\ShowSampleA {fm} {leftarrow} + {leftarrow(fullcircle,3,2)} + +\ShowSampleA {fm} {rightarrow} + {rightarrow(fullcircle,3,2)} + +\ShowSampleA {fm} {centerarrow} + {centerarrow(fullcircle,3,2)} + +\ShowSampleX {fm} {arrowhead} {draw arrowhead fullcircle} +\ShowSampleX {fm} {arrowpath} {draw arrowpath fullcircle} + +\ShowSampleA {mm} {buildcycle} + {buildcycle(fullcircle,fullsquare)} + +\ShowSampleA {fm} {circularpath} {circularpath(4)} +\ShowSampleA {fm} {squarepath} {squarepath(4)} +\ShowSampleA {fm} {linearpath} {linearpath(4)} + +\stopsection + +\startsection[title={Transformations}] + +\index{transformations} + +\ShowSampleB {mp} {path scaled numeric} {fullcircle} {fullcircle scaled .50} +\ShowSampleB {mp} {path xscaled numeric} {fullcircle} {fullcircle xscaled .25} +\ShowSampleB {mp} {path yscaled numeric} {fullcircle} {fullcircle yscaled .25} +\ShowSampleB {mp} {path zscaled pair} {fullcircle} {fullcircle zscaled (2,.25)} +\ShowSampleB {mp} {path xyscaled numeric/pair} {fullcircle} {fullcircle xyscaled (.5,.7)} +\ShowSampleB {mp} {path xyscaled pair} {fullcircle} {fullcircle xyscaled (2,.25)} +\ShowSampleB {mp} {path shifted pair} {fullcircle} {fullcircle shifted (2,.25)} + +\ShowSampleB {fm} {path leftenlarged numeric} {fullsquare} {fullsquare leftenlarged .25} +\ShowSampleB {fm} {path topenlarged numeric} {fullsquare} {fullsquare topenlarged .25} +\ShowSampleB {fm} {path rightenlarged numeric} {fullsquare} {fullsquare rightenlarged .25} +\ShowSampleB {fm} {path bottomenlarged numeric} {fullsquare} {fullsquare bottomenlarged .25} + +\ShowSampleB {fm} {path enlarged numeric} {fullcircle} {fullcircle enlarged .25} +\ShowSampleB {fm} {path enlarged pair} {fullcircle} {fullcircle enlarged (1,.25)} +\ShowSampleB {fm} {path llenlarged numeric} {fullcircle} {fullcircle llenlarged .25} +\ShowSampleB {fm} {path lrenlarged numeric} {fullcircle} {fullcircle lrenlarged .25} +\ShowSampleB {fm} {path urenlarged numeric} {fullcircle} {fullcircle urenlarged .25} +\ShowSampleB {fm} {path ulenlarged numeric} {fullcircle} {fullcircle ulenlarged .25} +\ShowSampleB {fm} {path llenlarged pair} {fullcircle} {fullcircle llenlarged (1,.25)} +\ShowSampleB {fm} {path lrenlarged pair} {fullcircle} {fullcircle lrenlarged (1,.25)} +\ShowSampleB {fm} {path urenlarged pair} {fullcircle} {fullcircle urenlarged (1,.25)} +\ShowSampleB {fm} {path ulenlarged pair} {fullcircle} {fullcircle ulenlarged (1,.25)} +\ShowSampleB {fm} {path llmoved numeric} {fullcircle} {fullcircle llmoved .25} +\ShowSampleB {fm} {path lrmoved numeric} {fullcircle} {fullcircle lrmoved .25} +\ShowSampleB {fm} {path urmoved numeric} {fullcircle} {fullcircle urmoved .25} +\ShowSampleB {fm} {path ulmoved numeric} {fullcircle} {fullcircle ulmoved .25} +\ShowSampleB {fm} {path llmoved pair} {fullcircle} {fullcircle llmoved (1,.25)} +\ShowSampleB {fm} {path lrmoved pair} {fullcircle} {fullcircle lrmoved (1,.25)} +\ShowSampleB {fm} {path urmoved pair} {fullcircle} {fullcircle urmoved (1,.25)} +\ShowSampleB {fm} {path ulmoved pair} {fullcircle} {fullcircle ulmoved (1,.25)} +\ShowSampleB {mp} {path slanted numeric} {fullcircle} {fullcircle slanted .5} +\ShowSampleB {mp} {path rotated numeric} {fullsquare} {fullsquare rotated 45} + +\ShowSampleB {mm} {path rotatedaround(pair,numeric)} {fullsquare} {fullsquare rotatedaround((.25,.5),45)} +\ShowSampleB {mm} {path reflectedabout(pair,pair)} {fullcircle} {fullcircle reflectedabout((.25,-1),(.25,+1))} +\ShowSampleB {mp} {reverse path} {fullcircle} {reverse fullcircle shifted(.5,0)} +\ShowSampleB {mm} {counterclockwise path} {fullcircle} {counterclockwise fullcircle shifted(.5,0)} +\ShowSampleB {mm} {tensepath path} {fullcircle} {tensepath fullcircle} + +\ShowSampleB {mp} {subpath (numeric,numeric) of path} {fullcircle} {subpath (1,5) of fullcircle} +\ShowSampleB {mm} {path cutbefore pair} {fullcircle} {fullcircle cutbefore point 3 of fullcircle} +\ShowSampleB {mm} {path cutafter pair} {fullcircle} {fullcircle cutafter point 3 of fullcircle} +\ShowSampleB {mm} {path cutends .1} {fullcircle} {fullcircle cutends .5} + +\ShowSampleC {mp} {llcorner path} {fullcircle} {llcorner fullcircle} +\ShowSampleC {mp} {lrcorner path} {fullcircle} {lrcorner fullcircle} +\ShowSampleC {mp} {urcorner path} {fullcircle} {urcorner fullcircle} +\ShowSampleC {mp} {ulcorner path} {fullcircle} {ulcorner fullcircle} +\ShowSampleC {mm} {center path} {fullcircle} {center fullcircle} + +\ShowSampleD {fm} {boundingbox path} {fullcircle} {boundingbox fullcircle} +\ShowSampleD {fm} {boundingcircle path} {fullsquare} {boundingcircle fullsquare} +\ShowSampleD {fm} {innerboundingbox path} {fullcircle} {innerboundingbox fullcircle} +\ShowSampleD {fm} {outerboundingbox path} {fullcircle} {outerboundingbox fullcircle} + +\ShowSampleDD {fm} {bottomboundary path} {fullcircle} {bottomboundary fullcircle} +\ShowSampleDD {fm} {leftboundary path} {fullcircle} {leftboundary fullcircle} +\ShowSampleDD {fm} {topboundary path} {fullcircle} {topboundary fullcircle} +\ShowSampleDD {fm} {rightboundary path} {fullcircle} {rightboundary fullcircle} + +\ShowSampleP {fm} {bbwidth path} {draw textext(decimal bbwidth (fullcircle xscaled 100 yscaled 200))} +\ShowSampleP {fm} {bbwidth path} {draw textext(decimal bbheight (fullcircle xscaled 100 yscaled 200))} + +\ShowSampleE {fm} {path/picture xsized numeric} {xsized 3cm} {currentpicture xsized 5cm} +\ShowSampleE {fm} {path/picture ysized numeric} {ysized 2cm} {currentpicture ysized 2cm} +\ShowSampleE {fm} {path/picture xysized numeric} {xysized (3cm,2cm)} {currentpicture xysized (3cm,2cm)} + +\ShowSampleP {fm} + {area path} + {draw area ((0,10)--(20,20)--(30,5)--(40,10)--(50,5)--(60,5))} + +\ShowSampleT {mp} + {setbounds picture} + {draw fullcircle ; setbounds currentpicture to unitsquare} + {draw fullcircle scaled .5 InGray; setbounds currentpicture to unitsquare scaled .5} + +\ShowSampleT {mm} + {clip path} + {fill fullcircle ; clip currentpicture to fullsquare scaled 0.9} + {fill fullcircle scaled 1 InRed ; clip currentpicture to fullsquare scaled 0.9} + +\ShowSampleT {mm} + {path peepholed path} + {fill (fullcircle peepholed fullsquare)} + {fill (fullcircle peepholed fullsquare) InRed} + +\ShowSampleT {fm} + {anchored} + {draw anchored.urt(textext("ll"),origin)} + {draw anchored.urt(textext("ll") xsized (5mm/Scale),origin) InRed ;} + +% \ShowSampleT {fm} +% {autoalign} +% {draw textext.autoalign(260)("260")} +% {draw textext.autoalign(260)("260")} + +% draw textext.autoalign(260)("\strut oeps 3") ; + +\ShowSampleX {fm} + {path crossingunder path} + {draw (fullsquare rotated 45) crossingunder fullsquare} + +\stopsection + +\startsection[title={Points}] + +\index{points} + +%ShowSampleF {mp} {center path} {fullcircle} {center fullcircle} +\ShowSampleF {mm} {top pair} {fullcircle} {top center fullcircle} +\ShowSampleF {mm} {bot pair} {fullcircle} {bot center fullcircle} +\ShowSampleF {mm} {lft pair} {fullcircle} {lft center fullcircle} +\ShowSampleF {mm} {rt pair} {fullcircle} {rt center fullcircle} +\ShowSampleF {mp} {point numeric of path} {fullcircle} {point 2 of fullcircle} +\ShowSampleF {fm} {point numeric on path} {fullcircle} {point .5 on fullcircle} +\ShowSampleF {fm} {point numeric along path} {fullcircle} {point 1cm along fullcircle} +\ShowSampleF {mp} {precontrol numeric of path} {fullcircle} {precontrol 2 of fullcircle} +\ShowSampleF {mp} {postcontrol numeric of path} {fullcircle} {postcontrol 2 of fullcircle} +\ShowSampleF {mp} {directionpoint pair of path} {fullcircle} {directionpoint (2,3) of fullcircle} + +\ShowSampleG {mc} {numeric[pair,pair]} {(1,1)} {.5[(0,0),(1,1)]} + +\ShowSampleH {mm} {path intersectionpoint path} {fullcircle} {fulldiamond} + {fullcircle intersectionpoint fulldiamond} + +\ShowSampleHH {mm} {interpath(numeric,path,path} + {interpath(.8,fullcircle,fullsquare)} + +\ShowSampleHH {fm} {interpolated(numeric,path,path} + {interpolated(.8,fullcircle,fullsquare)} + +\ShowSampleO {mm} {right} {draw left} +\ShowSampleO {mm} {up} {draw up} +\ShowSampleO {mm} {left} {draw left} +\ShowSampleO {mm} {down} {draw down} + +\stopsection + +\startsection[title={Colors}] + +\index{colors} + +\ShowSampleI {mp} {withcolor rgbcolor} {withcolor (.625,0,0)} +\ShowSampleI {mp} {withrgbcolor rgbcolor} {withrgbcolor (.625,0,0)} +\ShowSampleI {mp} {withcmykcolor cmykcolor} {withcmykcolor (.375,0,0,0)} +\ShowSampleI {mp} {withgray / withgrey numeric} {withgray .625} +\ShowSampleI {mp} {withcolor namedcolor} {withcolor namedcolor("darkblue")} +\ShowSampleI {mp} {withcolor spotcolor} {withcolor spotcolor("tempone",red/2)} +\ShowSampleI {mp} {withcolor multitonecolor} {withcolor .2 * multitonecolor("temptwo",blue/2,yellow/3)} + +Remark: at the time of this writing only Acrobat shows spot- and multitonecolors +properly. Possible indications of a viewing problem are factors not being applied +(in the page stream) or colors that are way off. + +\ShowSampleU {mp} {red} {fill fullcircle scaled 2 withcolor red/2} +\ShowSampleU {mp} {green} {fill fullcircle scaled 2 withcolor green/2} +\ShowSampleU {mp} {blue} {fill fullcircle scaled 2 withcolor blue/2} +\ShowSampleU {mp} {cyan} {fill fullcircle scaled 2 withcolor cyan/2} +\ShowSampleU {mp} {magenta} {fill fullcircle scaled 2 withcolor magenta/2} +\ShowSampleU {mp} {yellow} {fill fullcircle scaled 2 withcolor yellow/2} +\ShowSampleU {mp} {black} {fill fullcircle scaled 2 withcolor black/2} +\ShowSampleU {mp} {white} {fill fullcircle scaled 2 withcolor white/2} + +\ShowSampleU {mp} {blackcolor} {fill fullcircle withcolor blackcolor red} + +%ShowSampleI {fm} {withcolor cmyk(c,m,y,k)} {withcolor cmyk(0,.625,.625,0)} +%ShowSampleI {fm} {withcolor transparent(n.m,color)} {withcolor transparent(1,.625,red)} + +\ShowSampleI {fm} {withtransparency(num,num)} {withcolor red withtransparency (1,.625)} + +% \ShowSampleZ {fm} {withshade numeric} {Shades need to be declared before they can be (re)used.} + +\startMPinclusions + defineshade cshade withshademethod "circular" ; + defineshade lshade withshademethod "linear" ; +\stopMPinclusions + +\ShowSampleW {fm} {shaded someshade } + {fill fullsquare shaded lshade} + {fill fullsquare scaled 2cm shaded lshade} + +This assumes the definition: + +\starttyping +defineshade lshade withshademethod "linear" ; +\stoptyping + +\ShowSampleW {fm} {shaded someshade} + {fill fullcircle shaded cshade} + {fill fullcircle scaled 2cm shaded cshade} + +This assumes the definition: + +\starttyping +defineshade cshade withshademethod "circular" ; +\stoptyping + +% withshadefactor 1 +% withshadedomain (0,1) +% withshadecolors (black,white) +% withtransparency (1,.5) + +% \startMPcode +% fill fullcircle scaled 3cm +% shaded myshade +% withshadefactor 0.7 +% ; +% \stopMPcode + +% \startMPcode +% fill fullcircle scaled 3cm +% shaded myshade +% withshadecolors (red,green) +% withshadefactor 1 +% withtransparency (1,.75) +% ; +% \stopMPcode + +% \startMPcode +% fill fullcircle scaled 3cm +% shaded myshade ; +% withshadefactor 1 +% withshadedomain (0,1) +% withshadecolors (green,blue) +% withtransparency (1,.5) +% ; +% \stopMPcode + +% \startMPcode +% fill fullcircle scaled 3cm +% shaded myshade ; +% withshadefactor 1 +% withshadedomain (0,1) +% withcolor blue shadedinto yellow +% withtransparency (1,.5) +% ; +% \stopMPcode + +\ShowSampleV {mp} + {basiccolors} + {for i=0 upto 21 : fill ... withcolor basiccolors[i] ; endfor} + {for i=0 upto 21 : fill fullcircle shifted (i,0) withcolor basiccolors[i] ; endfor} + +\stopsection + +\startsection[title={Attributes}] + +\index{attributes} + +\ShowSampleII {mp} {dashed withdots} {dashed withdots} +\ShowSampleII {mp} {dashed evenly} {dashed evenly} +\ShowSampleII {mp} {dashed oddly} {dashed oddly} +\ShowSampleII {mp} {dashpattern} {dashed dashpattern (on .1 off .2 on .3 off .4)} +\ShowSampleII {mp} {undashed} {dashed evenly undashed} + +\ShowSampleJ {mm} {pencircle transform} {pencircle} +\ShowSampleJ {mm} {pensquare transform} {pensquare} +\ShowSampleJ {mm} {penrazor transform} {penrazor} +\ShowSampleK {mm} {penspeck transform} {penspeck} + +\ShowSampleL {mm} {draw} {fullcircle} +\ShowSampleL {mm} {fill} {fullcircle} +\ShowSampleL {mm} {filldraw} {fullcircle} +\ShowSampleL {mm} {drawfill} {fullcircle} +\ShowSampleL {mm} {drawdot} {origin} +\ShowSampleL {mm} {drawarrow} {fullcircle} +\ShowSampleL {mm} {drawdblarrow} {fullcircle} + +\ShowSampleL {fm} {eofill} {fullcircle} + +\ShowSampleM {mm} {undraw} {fullcircle} +\ShowSampleM {mm} {unfill} {fullcircle} +\ShowSampleM {mm} {unfilldraw} {fullcircle} +\ShowSampleM {mm} {undrawfill} {fullcircle} +\ShowSampleM {mm} {undrawdot} {origin} + +\ShowSampleQ {mm} {cutdraw} {origin--(1,1)} + +\ShowSampleN {mv} {butt} {linecap := butt} {(0,.5)--(.5,0)--(1,1)} +\ShowSampleN {mv} {rounded} {linecap := rounded} {(0,.5)--(.5,0)--(1,1)} +\ShowSampleN {mv} {squared} {linecap := squared} {(0,.5)--(.5,0)--(1,1)} + +\ShowSampleN {mv} {mitered} {linejoin := mitered} {(0,.5)--(.5,0)--(1,1)} +\ShowSampleN {mv} {rounded} {linejoin := rounded} {(0,.5)--(.5,0)--(1,1)} +\ShowSampleN {mv} {beveled} {linejoin := beveled} {(0,.5)--(.5,0)--(1,1)} + +\ShowSampleR {fm} {inverted picture} {inverted currentpicture} +\ShowSampleR {fm} {picture uncolored color} {currentpicture uncolored green} +\ShowSampleR {fm} {picture softened numeric} {currentpicture softened .8} +\ShowSampleR {fm} {picture softened color} {currentpicture softened (.7,.8,.9)} +\ShowSampleR {fm} {grayed picture} {grayed currentpicture} + +\stopsection + +\startsection[title={Text}] + +\index{text} + +\ShowSampleO {mm} {label} {label("MetaFun",origin)} +\ShowSampleO {mm} {label.top} {label.top("MetaFun",origin)} +\ShowSampleO {mm} {label.bot} {label.bot("MetaFun",origin)} +\ShowSampleO {mm} {label.lft} {label.lft("MetaFun",origin)} +\ShowSampleO {mm} {label.rt} {label.rt("MetaFun",origin)} +\ShowSampleO {mm} {label.llft} {label.llft("MetaFun",origin)} +\ShowSampleO {mm} {label.lrt} {label.lrt("MetaFun",origin)} +\ShowSampleO {mm} {label.urt} {label.urt("MetaFun",origin)} +\ShowSampleO {mm} {label.ulft} {label.ulft("MetaFun",origin)} + +\ShowSampleW {mp} {dotlabel} + {dotlabel.bot("\tttf metafun",(2cm,1cm))} + {dotlabel.bot("\tttf metafun",(2cm,1cm))} + +\ShowSampleW {mp} {dotlabels + range .. thru ..} + {z1 = ... ; dotlabels.bot(range 1 thru 3)} + {z1=(0,0); z2=(10mm,10mm); z3=(20mm,15mm); ; z4=(30mm,5mm); dotlabels.bot(range 1 thru 4)} + +\ShowSampleW {mp} {labels + range .. thru ..} + {z1 = ... ; labels.bot(range 1 thru 3)} + {z1=(0,0); z2=(10mm,10mm); z3=(20mm,15mm); ; z4=(30mm,5mm); labels.bot(range 1 thru 4)} + +\ShowSampleQQ {fm} + {thelabel(string,pair)} + {draw thelabel("MetaFun",(2cm,0))} + +\ShowSampleQQ {fm} + {formatted(string)} + {draw textext(formatted("@0.5f",1.234))} + +\ShowSampleQQ {fm} + {format(string) : graph package} + {draw textext(format("@5E-2",1.234))} + +\ShowSampleP {mp} + {btex text etex} + {draw btex MetaTeX etex} + +\ShowSampleQQ {fm} + {textext(string)} + {draw textext("MetaFun")} + +\ShowSampleQQ {fm} + {thetextext(string,pair)} + {draw thetextext("MetaFun",(2cm,0))} + +% \ShowSampleQQ {fm} +% {graphictext string ...} +% {graphictext "MetaFun"} + +\ShowSampleQQQ {fm} + {outlinetext.d("string")(d)} + {draw outlinetext.d("MetaFun")(InRed)} + +\ShowSampleQQQ {fm} + {outlinetext.f("string")(f)} + {draw outlinetext.f("MetaFun")(InYellow)} + +\ShowSampleQQQ {fm} + {outlinetext.b("string")(f)(d)} + {draw outlinetext.b("MetaFun")(InYellow)(InRed)} + +\ShowSampleQQQ {fm} + {outlinetext.r("string")(d)(f)} + {draw outlinetext.r("MetaFun")(InRed)(InYellow)} + +\ShowSampleUU {fm} + {outlinetext.p("string")} + {draw outlinetext.p("MetaFun")} + +\stopsection + +\startsection[title={Control}] + +\index{loops} + +\ShowSampleU {mp} {for (positive step) until} {for i=0 step 2 until 8: drawdot (i,0) ; endfor} +\ShowSampleU {mp} {for (negative step) until} {for i=6 step -2 until 0: drawdot (i,0) ; endfor} +\ShowSampleU {mm} {for upto} {for i=0 upto 12: drawdot (i,0) ; endfor} +\ShowSampleU {mm} {for downto} {for i=10 downto 0: drawdot (i,0) ; endfor} +\ShowSampleU {mm} {forsuffixes} {forsuffixes i=1,4,6,12: drawdot (i,0) ; endfor} + +\stopsection + +\startsection[title={Graphics}] + +\index{graphics} + +\ShowSampleS {fm} + {loadfigure string number numeric ...} + {loadfigure "mycow.mp" number 1 scaled .25} + +\ShowSampleS {fm} + {externalfigure string ...} + {draw externalfigure "mycow.pdf" scaled 3cm} + +\ShowSampleT {fm} {addbackground text} + {addbackground withcolor .625 yellow} + {fill fullcircle xyscaled (2,1) InRed; addbackground InYellow} + +\ShowSampleQQ {mm} {image (text)} + {draw image(draw fullcircle) xscaled 4cm yscaled 1cm} + +\ShowSampleT {mm} {decorated (text) text} + {draw decorated (....) withcolor red} + {draw decorated (fill fullcircle) InRed} + +\ShowSampleT {mm} {undecorated (text) text} + {draw undecorated (.... withcolor yellow) withcolor red} + {draw undecorated (fill fullcircle InYellow) InRed} + +\ShowSampleT {mm} {redecorated (text) text} + {draw redecorated (.... withcolor yellow) withcolor red} + {draw redecorated (fill fullcircle InYellow) InRed} + +\ShowSampleS {mm} + {bitmapimage (w,h,data)} + {draw bitmapimage (2,2,"114477AA") rotated 15 scaled 4cm} + +\ShowSampleT {mm} + {withmask string} + {draw externalfigure "m-1.png" scaled 2cm withmask "m-2.png"} + {Scale := 1 ; + draw externalfigure "m-2.png" scaled 2cm shifted (-3cm,0) ; + draw externalfigure "m-1.png" scaled 2cm shifted (-6cm,0) ; + draw externalfigure "m-1.png" scaled 2cm withmask "m-2.png"} + +\stopsection + +\stopchapter + +\stopcomponent + +%% draw leftpath fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ; +%% draw reverse leftpath (reverse fullcircle scaled 2cm) withpen pencircle scaled 1mm withcolor .625yellow ; +%% draw rightpath fullcircle scaled 3cm withpen pencircle scaled 1mm withcolor .625white ; +%% +%% path p ; p := (0,0) .. (1,2) .. cycle ; +%% draw leftpath p scaled 1cm withpen pencircle scaled 1mm withcolor .625red ; +%% draw reverse leftpath (reverse p scaled 2cm) withpen pencircle scaled 1mm withcolor .625yellow ; +%% draw rightpath p scaled 3cm withpen pencircle scaled 1mm withcolor .625white ; diff --git a/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex b/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex new file mode 100644 index 000000000..02c502cf0 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex @@ -0,0 +1,60 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-conventions + +\environment metafun-environment + +\startchapter[title={Conventions}] + +\startsection[title={Suffixes}] + +One characteristic of using \METAFUN\ in \CONTEXT\ is that it is basically one +long run. The code snippets become figures that then get converted to \PDF\ and +embedded. If text is involved, each figure is actually processed twice, once to +identify what needs to be typeset, and once with the result(ing metrics). +Normally that gets unnoticed. You can check for the state by consulting the +boolean \type {mfun_trial_run}. + +A consequence of the one run cq.\ multiple runs is that you need to be careful with +undefined or special variables. Consider the following: + +\starttyping +vardef foo@#(text t) = + save s ; string s ; s := str @# ; + if length(s) > 0 : + textext(s) + else : + nullpicture + fi +enddef ; +\stoptyping + +The following works ok in the first run when bar is undefined: + +\starttyping +draw foo.bar("a") ; +\stoptyping + +But if afterwards we say: + +\starttyping +vardef bar(expr x) = + 123 +enddef ; +\stoptyping + +and expand \type {foo.bar} again we will get an error message because this time +\type {bar} expands. Suffixes are always expanded! + +The lesson is: when you get unexpected results or errors, check your variable +definitions. You can use the \type {begingroup} and \type {endgroup} primitives +to protect your variables but then you also need to explicitly use \type {save} +to store their meanings and allocate new ones after that inside the group. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-styles.tex b/doc/context/sources/general/manuals/metafun/metafun-styles.tex new file mode 100644 index 000000000..f82359117 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-styles.tex @@ -0,0 +1,445 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-styles + +\environment metafun-environment + +\startchapter[title={Defining styles}] + +\index {layout} +\index {styles} + +\startintro + +Since the integration of \METAPOST\ into \CONTEXT, a complete new range of layout +fetaures became available. In this document we have introduced several ways to +include graphics in your document definition. In this chapter we go one step +further and make dynamic graphics part of a document style. + +\stopintro + +\startsection[title={Adaptive buttons}] + +So far we have seen a lot of graphic ingredients that you can use to make your +documents more attractive. In this chapter we will define a simple document +style. This style was written for the \PDFTEX\ presentations at the TUG 2000 +conference in Oxford (UK). + +This style exploits a few tricks, like graphics calculated using positional +information. It also demonstrates how you can make menu buttons that dynamically +adapt their shapes to the rest of the page layout. + +\startbuffer[screens] +\startlinecorrection[blank] +\setupcombinations[distance=.0125\textwidth] +\startcombination[5*1] + {\typesetfile[mfun-77\ScrNum.tex][page=1,width=.19\textwidth]} {page 1} + {\typesetfile[mfun-77\ScrNum.tex][page=2,width=.19\textwidth]} {page 2} + {\typesetfile[mfun-77\ScrNum.tex][page=3,width=.19\textwidth]} {page 3} + {\typesetfile[mfun-77\ScrNum.tex][page=4,width=.19\textwidth]} {page 4} + {\typesetfile[mfun-77\ScrNum.tex][page=5,width=.19\textwidth]} {page 5} +\stopcombination +\stoplinecorrection +\stopbuffer + +\def\ScrNum{1} \getbuffer[screens] + +Later we will see an instance with some more randomness in the graphics. While +writing this style, the random alternative made me think of those organic +buildings with non equal windows |<|we have a few of those in The Netherlands|>|, +so I decided to label this style as \type {pre-organic}. If you use \CONTEXT, you +can load this style with: + +\starttyping +\usemodule[pre-organic] +\stoptyping + +At the end of this file, there is a small test file, so when you process the file +\type {s-pre-19.tex} \footnote {This style is the 19\high{th} presentation style. +Those numbered styles are internally mapped onto more meaningful names like in +this case \type {pre-organic}.} with the options \type {--mode=demo} and \type +{--pdf}, you will get a demo document. + +We use one of the standard screen \quote {paper} sizes, and map it onto the same +size, so that we get a nicely cropped page. Other screen sizes are \type {S4} and +\type {S5}. + +\starttyping +\setuppapersize[S6][S6] +\stoptyping + +Like in this \METAFUN\ manual, we use the Palatino as main bodyfont. This font is +quite readable on even low resolution screens, although I admit that this style +is developed using an $1400\times1050$ pixel \kap {lcd} screen, so the author may +be a little biased. + +\starttyping +\setupbodyfont[ppl] +\stoptyping + +The layout specification sets up a text area and a right edge area where the +menus will go (see \in {chapter} [sec:page] for a more in depth discussion on the +layout areas). Watch how we use a rather large edge distance. By setting the +header and footer dimensions to zero, we automatically get rid of page body +ornaments, like the page number. + +\starttyping +\setuplayout + [topspace=48pt, + backspace=48pt, + cutspace=12pt, + width=400pt, + margin=0cm, + rightedge=88pt, + rightedgedistance=48pt, + header=0cm, + footer=0cm, + height=middle] +\stoptyping + +We use a moderate, about a line height, inter||paragraph white space. + +\starttyping +\setupwhitespace[big] +\stoptyping + +Of course we use colors, since on computer displays they come for free. + +\starttyping +\setupcolors[state=start] + +\definecolor [red] [r=.75] +\definecolor [yellow] [r=.75,g=.75] +\definecolor [gray] [s=.50] +\definecolor [white] [s=.85] +\stoptyping + +Because it is an interactive document, we have to enable hyperlinks and alike. +However, in this style, we disable the viewer's \quote {highlight a hyperlink +when it's clicked on} feature. We will use a menu, so we enable menus. Later we +will see the contrast color |<|hyperlinks gets that color when we are already on +the location|>| in action. + +\starttyping +\setupinteraction + [state=start, + click=off, + color=red, + contrastcolor=gray, + menu=on] +\stoptyping + +The menu itself is set up as follows. Because we will calculate menu buttons +based on their position on the page, we have to keep track of the positions. +Therefore, we set the \type {position} variable to \type {yes}. + +\starttyping +\setupinteractionmenu + [right] + [frame=off, + position=yes, + align=middle, + topoffset=-.75cm, + bottomoffset=-.75cm, + color=gray, + contrastcolor=gray, + style=bold, + before=, + after=] +\stoptyping + +The menu content is rather sober: just a list of topics and a close button. Later +we will define the command that generates topic entries. The alternative \type +{right} lets the topic list inherit its characteristics from the menu. + +\starttyping +\startinteractionmenu[right] + \placelist[Topic][alternative=right] + \vfill + \but [CloseDocument] close \\ +\stopinteractionmenu +\stoptyping + +We have now arrived at the more interesting part of the style definition: the +graphic that goes in the page background. Because this graphic will change, we +define a useable \METAPOST\ graphic. Page backgrounds are recalculated each page, +opposite to the other backgrounds that are calculated when a new background is +defined, or when repetitive calculation is turned on. + +\starttyping +\setupbackgrounds [page] [background=page] +\defineoverlay [page] [\useMPgraphic{page}] +\setupMPvariables [page] [alternative=3] +\stoptyping + +We will implement three alternative backgrounds. First we demonstrate the +relatively simple super ellipsed one. The main complication is that we want the +button shapes to follow the right edge of the curve that surrounds the text. We +don't know in advance how many lines of text there will be in a button, and we +also don't know at what height it will end up. Therefore, we need to calculate +each button shape independently and for that purpose we need to know its position +(see \in {chapter} [sec:positioning]). In \in {figure} [fig:style] you can see +what lines we need in order to be calculate the button shapes. + +\startpostponing + +\startmode[screen] + \placefigure + [here][fig:style] + {The lines used to calculate the button shapes.} + {\externalfigure[mfun-774.pdf][page=1,height=.85\textheight]} +\stopmode + +\startnotmode[screen] + \placefigure + [here][fig:style] + {The auxiliary lines used to calculate the button shapes.} + {\rotate{\externalfigure[mfun-774.pdf][page=1,height=\textwidth]}} +\stopnotmode + +\page + +\stoppostponing + +We separate the calculation of the button shape from the rest by embedding it in +its own usable graphic container. The \type {StartPage}||\type {StopPage} pair +takes care of proper placement of the whole graphic. + +\starttyping +\startuseMPgraphic{page} + + \includeMPgraphic{rightsuperbutton} + + StartPage ; + + path p, q ; pickup pencircle scaled 3pt ; + + p := Field[Text][Text] enlarged 36pt superellipsed .90 ; + + fill Page withcolor \MPcolor{yellow} ; + fill p withcolor \MPcolor{white} ; + draw p withcolor \MPcolor{red} ; + + p := Field[Text][Text] enlarged 48pt superellipsed .90 ; + + def right_menu_button (expr nn, rr, pp, xx, yy, ww, hh, dd) = + if (pp>0) and (rr>0) : + q := rightsuperbutton(p,xx,yy,RightEdgeWidth,hh) ; + fill q withcolor \MPcolor{white} ; + draw q withcolor if rr=2 : \MPcolor{gray} + else : \MPcolor{red} fi ; + fi ; + enddef ; + + \MPmenubuttons{right} + + StopPage ; +\stopuseMPgraphic +\stoptyping + +The \TEX\ macro \type {\MPmenubuttons} expands into a list of (in this case four) +calls to the \METAPOST\ macro \type {right_menu_button}. This list is generated +by \CONTEXT\ when it generates the menu. Because the page background is applied +last, this list is available at that moment. + +\starttyping +... (expr nn, rr, pp, xx, yy, ww, hh, dd) ... +\stoptyping + +This rather long list of arguments represents the following variables: number, +referred page, current page, x coordinate, y coordinate, width, height and depth. +The last six variables originate from the positioning mechanism. Because the +variables are only available after a second \TEX\ pass, we only draw a button +shape when the test for the page numbers succeeds. + +\starttyping +\startuseMPgraphic{rightsuperbutton} + vardef rightsuperbutton (expr pat, xpos, ypos, wid, hei) = + + save p, ptop, pbot, t, b, edge, shift, width, height ; + path p, ptop, pbot ; pair t, b ; + numeric edge, shift, width, height ; + + edge := xpos + wid ; shift := ypos + hei ; + + p := rightpath pat ; + + ptop := ((-infinity,shift)--(edge,shift)) ; + pbot := ((-infinity,shift-hei)--(edge,shift-hei)) ; + + t := p intersectionpoint ptop ; + b := p intersectionpoint pbot ; + + p := subpath(0,xpart (p intersectiontimes ptop)) of p ; + p := subpath(xpart (p intersectiontimes pbot),length(p)) of p ; + + (p -- t -- point 1 of ptop & + point 1 of ptop -- point 1 of pbot & + point 1 of pbot -- b + -- cycle) + + enddef ; +\stopuseMPgraphic +\stoptyping + +The calculation of the button itself comes down to combining segments of the main +shape and auxiliary lines. The \type {rightpath} macro returns the right half of +the path provided. This half is shown as a non dashed line. + +Topics are identified with \type {\Topic}, which is an instance of chapter +headings. The number is made invisible. Since it still is a numbered section +header, \CONTEXT\ will write the header to the table of contents. + +\starttyping +\definehead [Topic] [chapter] +\setuphead [Topic] [number=no] +\stoptyping + +We will use a bold font in the table of contents. We also force a complete list. + +\starttyping +\setuplist + [Topic] + [criterium=all, + style=bold, + before=, + after=] +\stoptyping + +The \type {\TitlePage} macro looks horrible, because we want to keep the +interface simple: a list of small sentences, separated by \type {\\}. + +\starttyping +\def\TitlePage#1% + {\startstandardmakeup + \switchtobodyfont[big] + \def\\{\vfill\bfb\let\\=\par} + \bfd\setupinterlinespace\gray + \vskip.5cm#1\\\vskip.5cm % \\ is really needed -) + \stopstandardmakeup} +\stoptyping + +A presentation that uses this style, may look like the one below. You can choose +among three alternatives. + +\starttyping +\useenvironment[pre-organic] \setupoutput[pdftex] + +\setupMPvariables[page][alternative=1] + +\starttext + +\TitlePage + {A Few Nice Quotes\\ + A Simple Style Demo\\ + Hans Hagen, August 2000} + +\Topic {Douglas R. Hofstadter} \input douglas \page +\Topic {Donald E. Knuth} \input knuth \page +\Topic {Edward R. Tufte} \input tufte \page +\Topic {Hermann Zapf} \input zapf \page + +\stoptext +\stoptyping + +We will not implement the two other alternative shapes: squeezed and randomized. + +\def\ScrNum{2} \getbuffer[screens] +\def\ScrNum{3} \getbuffer[screens] + +We combine all alternatives into one page graphic. The alternative is chosen by +setting the \type {alternative} variable, as we demonstrated in the example. + +\starttyping +\startuseMPgraphic{page} + + \includeMPgraphic{rightsuperbutton} + + StartPage ; + + numeric alternative, seed, superness, squeezeness, randomness ; + path p, q ; transform t ; +\stoptyping + +This is one of those cases where a transform variable is useful. We need to store +the random seed value because we want the larger path that is used in the +calculations to have the same shape. + +\starttyping + alternative := \MPvar{alternative} ; + seed := uniformdeviate 100 ; + + if alternative > 10 : + superness := .85 + ((\realfolio-1)/max(\lastpage,1)) * .25 ; + squeezeness := 12pt - ((\realfolio-1)/max(\lastpage,1)) * 10pt ; + else : + superness := .90 ; + squeezeness := 12pt ; + fi ; + + randomness := squeezeness ; + + alternative := alternative mod 10 ; +\stoptyping + +If you read closely, you will notice that when we add 10 to the alternative, we +get a page dependant graphic. So, in fact we have five alternatives. We use +\CONTEXT\ macros to fetch the (real) page number and the number of the last page. +In further calculations we use the lower alternative numbers, which is why we +apply a \type {mod}. + +The rest of the code is not so much different from the previous definition. The +hard coded point sizes match the page dimensions (600pt by 450pt) quite well. + +\starttyping + t := identity if alternative=3: shifted (9pt,-9pt) fi ; + + randomseed := seed ; + + p := Field[Text][Text] enlarged if + alternative = 1 : 36pt superellipsed superness elseif + alternative = 2 : 36pt squeezed squeezeness elseif + alternative = 3 : 36pt randomized randomness else + : 36pt fi ; + + pickup pencircle scaled 3pt ; + + fill Page withcolor \MPcolor{yellow} ; + fill p withcolor \MPcolor{white} ; + draw p withcolor \MPcolor{red} ; + + randomseed := seed ; + + p := ( Field[Text][Text] enlarged if + alternative = 1 : 48pt superellipsed superness elseif + alternative = 2 : 48pt squeezed squeezeness elseif + alternative = 3 : 36pt randomized randomness else + : 48pt fi ) transformed t ; + + def right_menu_button (expr nn, rr, pp, xx, yy, ww, hh, dd) = + if (pp>0) and (rr>0) : + q := rightsuperbutton(p,xx,yy,RightEdgeWidth,hh) ; + fill q withcolor \MPcolor{white} ; + draw q withcolor if rr=2 : \MPcolor{gray} + else : \MPcolor{red} fi ; + fi ; + enddef ; + + \MPmenubuttons{right} + + StopPage ; +\stopuseMPgraphic +\stoptyping + +When we choose the alternatives~21 and~22 we get this result: + +\def\ScrNum{5} \getbuffer[screens] +\def\ScrNum{6} \getbuffer[screens] + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-syntax.tex b/doc/context/sources/general/manuals/metafun/metafun-syntax.tex new file mode 100644 index 000000000..9407b1dd0 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-syntax.tex @@ -0,0 +1,1130 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +% eoclip: no postscript possible yet +% +% mpprocset mpxbreak + +% path expression -> path + +% listsize +% copylist +% sortlist +% shapedlist +% listtocurves +% listtolines + +\startcomponent metafun-syntax + +\environment metafun-environment + +\startchapter[title={\METAPOST\ syntax}] + +\index{syntax} +\index{language} + +\startintro + +In the \METAFONT\ book as well as the \METAPOST\ manual, you can find the exact +specification of the language. Below you find the full \METAPOST\ syntax, to +which we add the basic \METAFUN\ extensions. If this page looks too cryptic, you +can safely skip to the next chapter. We don't distinguish between primitives and +functionality defined in the \METAPOST\ format, simply because the core is kept +small and a macro package is supposed to extend that core. + +\stopintro + +% \startsection[title={Syntax diagrams}] + +The following syntax diagrams are derived from the diagrams in the \METAPOST\ +manual. The \mathematics {\rightarrow} represents \quote {means} and the +\mathematics {\vert} symbol stands for \quote {or}. + +The diagrams describe the hard coded \METAPOST\ syntax as well as most of the +macros and variables defined in the plain \METAPOST\ format that belongs to the +core of the system. They also include most of the fundamental \METAFUN\ commands. +We have omitted the \METAPOST\ and \METAFONT\ commands that make no sense any +more or are irrelevant for common usage. Specific \METAFUN\ modules are not +included here, only general tools, text helpers and extensions to the built||in +capabilities like transparency. If you feel that something is missing that should +be specified here, just let me know. + +\start \switchtobodyfont[8pt] % small] + +\StartSyntax +\S{atom} + \M \S{variable} \S{argument} + \O \S{number or fraction} + \O \S{internal variable} + \O \( \S{expression} \) + \O \L{begingroup} \S{statement list} \S{expression} \L{endgroup} + \O \S{nullary op} + \O \L{btex} \S{typesetting command} \L{etex} + % \O \L{verbatimtex} \S{typesetting command} \L{etex} + \O \S{pseudo function} +\StopSyntax + +\StartSyntax +\S{primary} + \M \S{atom} + \O \( \S{numeric expression} \L{,} \S{numeric expression} \) + \O \( \S{numeric expression} \L{,} \S{numeric expression} \L{,} \S{numeric expression} \) + \O \( \S{numeric expression} \L{,} \S{numeric expression} \L{,} \S{numeric expression} \L{,} \S{numeric expression} \) + \O \S{of operator} \S{expression} \L{of} \S{primary} + \O \S{numeric expression} \S{expression} \FL{along} \S{path expression} + \O \S{numeric expression} \S{expression} \FL{on} \S{path expression} + \O \S{unary op} \S{primary} + \O \L{str} \S{suffix} + \O \L{z} \S{suffix} + \O \S{numeric atom} \[ \S{expression} \L{,} \S{expression} \] + \O \S{scalar multiplication op} \S{primary} + \O \S{color expression} \FL{shadedinto} \S{color expression} + \O \S{picture expression} \FL{asgroup} \S{string expression} + \O \S{picture expression} \FL{onlayer} \S{string expression} +\StopSyntax + +\StartSyntax +\S{secondary} + \M \S{primary} + \O \S{secondary} \S{primary binop} \S{primary} + \O \S{secondary} \S{transformer} +\StopSyntax + +\StartSyntax +\S{tertiary} + \M \S{secondary} + \O \S{tertiary} \S{secondary binop} \S{secondary} +\StopSyntax + +\StartSyntax +\S{subexpression} + \M \S{tertiary} + \O \S{path expression} \S{path join} \S{path knot} +\StopSyntax + +\StartSyntax +\S{expression} + \M \S{subexpression} + \O \S{expression} \S{tertiary binop} \S{tertiary} + \O \S{path subexpression} \S{direction specifier} + \O \S{path subexpression} \S{path join} \L{cycle} +\StopSyntax + +\StartSyntax +\S{path knot} + \M \S{tertiary} +\StopSyntax + +\StartSyntax +\S{path join} + \M \L{--} + \O \S{direction specifier} \S{basic path join} \S{direction specifier} +\StopSyntax + +\StartSyntax +\S {direction specifier} + \M \S{empty} + \O \{ \L{curl} \S{numeric expression} \} + \O \{ \S{pair expression} \} + \O \{ \S{numeric expression} \L{,} \S{numeric expression} \} +\StopSyntax + +\StartSyntax +\S{basic path join} + \M \L{..} + \O \L{...} + \O \L{..} \S{tension} \L{..} + %O \L{..} \S{tension} \L{..} % check what got lost here + \O \L{..} \S{controls} \L{..} +\StopSyntax + +\StartSyntax % atleast added +\S{tension} + \M \L{tension} \S{numeric primary} + \O \L{tension} \L{atleast} \S{numeric primary} + \O \L{tension} \S{numeric primary} \L{and} \S{numeric primary} +\StopSyntax + +\StartSyntax +\S{controls} + \M controls \S{pair primary} + \O controls \S{pair primary} \L{and} \S{pair primary} +\StopSyntax + +\StartSyntax +\S{argument} + \M \S{symbolic token} +\StopSyntax + +\StartSyntax +\S{number or fraction} + \M \S{number} \L{/} \S{number} + \O \S{number} \Q{not followed by} \L{/} \S{number} +\StopSyntax + +\StartSyntax +\S{scalar multiplication op} + \M \L{+} \O \L{-} + \O \S{number or fraction} \Q{not followed by} \S{add op} \S{number} +\StopSyntax + +\StartSyntax +\S{transformer} + \M \L {rotated} \S {numeric primary} + \O \L {scaled} \S {numeric primary} + \O \L {shifted} \S {pair primary} + \O \L {slanted} \S {numeric primary} + \O \L {transformed} \S {transform primary} + \O \L {xscaled} \S {numeric primary} \O \L {yscaled} \S {numeric primary} \O \FL{xyscaled} \S {numeric or pair primary} + \O \L {zscaled} \S {pair primary} + \O \L {reflectedabout} \L \( \S{pair expression} \L{,} \S{pair expression} \) + \O \L {rotatedaround} \L \( \S{pair expression} \L{,} \S{numeric expression} \) + \O \FL{xsized} \S {numeric primary} \O \FL{ysized} \S {numeric primary} \O \FL{xysized} \S {numeric or pair primary} + \O \FL{blownup} \S {numeric or pair primary} + \O \FL{enlarged} \S {numeric or pair primary} + \O \FL{xstretched} \S {numeric primary} \O \FL{ystretched} \S{numeric primary} \O \FL{stretched} \S{numeric or pair primary} + \O \FL{shortened} \S {numeric or pair primary} + \O \FL{enlonged} \S {numeric or pair primary} + \O \FL{crossed} \S {numeric primary} + \O \FL{paralelled} \S {numeric primary} + \O \FL{curved} \S {numeric primary} + \O \FL{laddered} + \O \FL{leftenlarged} \S{numeric primary} \O \FL{llenlarged} \S{numeric primary} \O \FL{llmoved} \S{numeric primary} + \O \FL{rightenlarged} \S{numeric primary} \O \FL{lrenlarged} \S{numeric primary} \O \FL{lrmoved} \S{numeric primary} + \O \FL{topenlarged} \S{numeric primary} \O \FL{urenlarged} \S{numeric primary} \O \FL{urmoved} \S{numeric primary} + \O \FL{bottomenlarged} \S{numeric primary} \O \FL{ulenlarged} \S{numeric primary} \O \FL{ulmoved} \S{numeric primary} + \O \FL{randomized} \S{numeric or pair or color primary} + \O \FL{randomizedcontrols} \S{numeric or pair} + \O \FL{snapped} \S{numeric or pair primary} + \O \FL{cornered} \S{numeric or pair} + \O \FL{peepholed} \S{path expression} + \O \FL{smoothed} \S{numeric or pair} + \O \FL{squeezed} \S{numeric or pair primary} + \O \FL{superellipsed} \S{numeric primary} + \O \FL{randomshifted} \S{numeric or pair primary} + \O \FL{uncolored} \S{color primary} + \O \FL{softened} \S{numeric or color primary} + \O \FL{asgroup} \S{string primary} + \O \L {gobbled} \S{primary} + % + \O \FL {insideof} \S{path expression} + \O \FL {outsideof} \S{path expression} + \O \FL {crossinunder} \S{path expression} +\StopSyntax + +\StartSyntax +\S{numeric or pair primary} + \M \S{numeric primary} + \O \S{pair primary} +\StopSyntax + +\StartSyntax +\S{numeric or pair or color primary} + \M \S{numeric primary} + \O \S{pair primary} + \O \S{color primary} +\StopSyntax + +\StartSyntax +\S{numeric or color primary} + \M \S{numeric primary} + \O \S{color primary} +\StopSyntax + +\StartSyntax +\S{nullary op} + \M \L{false} \O \L{true} + \O \L{normaldeviate} + \O \L{nullpen} \O \L{nullpicture} \O \L{pencircle}% + \O \L{whatever} +\StopSyntax + +\StartSyntax +\S{unary op} + \M \S{type} + \O \L {ASCII} + \O \FL{asin} \O \FL{asinh} \O \FL{acos} \O \FL{acosh} \O \FL{atan} \O \L {cosd} \O \FL{cos} \O \FL{cosh} \O \FL{cot} \O \FL{cotd} \O \L {sind} \O \FL{sin} \O \FL{sinh} \O \FL{tand} \O \FL{tan} + \O \L {inverse} \O \FL{inv} \O \FL{invcos} \O \FL{invsin} \O \FL{invtan} + \O \FL{sqr} \O \L {sqrt} \O \L {pow} \O \FL{exp} \O \L {mexp} \O \L {mlog} \O \FL{ln} \O \FL{log} \O \L {uniformdeviate} + \O \L {abs} \O \L {round} \O \L {odd} \O \L {ceiling} \O \L {floor} + \O \L {dir} \O \L {angle} \O \L {length} \O \L {arclength} + \O \L {bbox} \O \FL{bbwidth} \O \FL{bbheight} + \O \L {bot} \O \L {lft} \O \L {rt} \O \L {top} \O \L {center} + \O \FL{colordecimals} \O \L {decimal} \O \FL{ddecimal} \O \FL{dddecimal} \O \FL{ddddecimal} \O \FL{condition} \O \FL{tostring} + \O \FL{boundingbox} \O \FL{outerboundingbox} \O \FL{innerboundingbox} \O \L {bbox} + \O \L {colorpart} \O {fontpart} \O \L {pathpart} \O \L {penpart} \O \L {textpart} \O \L {dashpart} + \O \L {redpart} \O \L {greenpart} \O \L {bluepart} \O \L {greypart} \O \L {graypart} + \O \L {cyanpart} \O \L {magentapart} \O \L {yellowpart} \O \L {blackpart} + \O \L {postscriptpart} \O \L {prescriptpart} + \O \L {clipped} \O \L {bounded} \O \L {stroked} \O \L {filled} \O \L {textual} + \O \FL{punked} \O \L{paralleled} + \O \FL{leftboundary} \O \FL{rightboundary} \O \FL{topboundary} \O \FL{bottomboundary} + \O \L {xpart} \O \L {xxpart} \O \L {xypart} \O \L {ypart} \O \L {yxpart} \O \L {yypart} + \O \L {oct} \O \L {hex} + \O \L {colortype} + \O \FL{grayed} \O \FL{greyed} + \O \L {llcorner} \O \L {lrcorner} \O \L {ulcorner} \O \L {urcorner} + \O \L {not} \O \L {known} \O \L {unknown} + \O \FL{blackcolor} \O \FL{whitecolor} \O \L {colormodel} + \O \L {char} \O \L {fontsize} + \O \L {cycle} \O \L {reverse} \O \L {counterclockwise} + \O \L {makepath} \O \L {makepen} + \O \L {unitvector} + \O \L {turningnumber} + \O \L {circularpath} \O \L {squarepath} \O \L {linearpath} + % maybe pseudo functions: + \O \FL{area} \O \FL{inverted} \O \FL{simplified} \O \FL{unspiked} +\StopSyntax + +\StartSyntax +\S{type} + \M \L{boolean} \O \L{numeric} \O \L{pair} \O \L{path} + \O \L{pen} \O \L{picture} \O \L{string} \O \L{transform} + \O \L{color} \O \L{cmykcolor} \O \FL {greycolor} \FL {graycolor}\O \L{rgbcolor} + \O \FL{property}\O \FL{transparency} + \O \L{outer} \O \L{inner} +\StopSyntax + +\StartSyntax +\S{primary binop} + \M \L{*} \O \L{/} \O \L{**} \O \L{and} + \O \L{dotprod} \O \L{div} \O \L{infont} \O \L{mod} +\StopSyntax + +\StartSyntax +\S{secondary binop} + \M \L{+} \O \L{-} \O \L{++} \O \L{+-+} \O \L{or} + \O \L{intersectionpoint} \O \L{intersectiontimes} +\StopSyntax + +\StartSyntax +\S{tertiary binop} + \M \L{&} \O \L{<} \O \L{<=} \O \L{<>} \O \L{=} \O \L{>} \O \L{>=} + \O \L{cutafter} \O \L{cutbefore} \O \FL{cutends} + \O \L{softjoin} +\StopSyntax + +\StartSyntax +\S{of operator} + \M \L{arctime} \O \L{direction} \O \L{directiontime} \O \L{directionpoint}% + \O \L{penoffset} \O \L{point} + \O \L{postcontrol} \O \L{precontrol} \O \L{subpath} \O \L{substring} + \O \L{takepower} +\StopSyntax + +\StartSyntax +\S{variable} + \M \S{predefined numeric variable} + \O \S{predefined path variable} + \O \S{predefined picture variable} + \O \S{predefined transform variable} + \O \S{predefined pair variable} + \O \S{predefined pen variable} + \O \S{predefined string variable} + \O \S{predefined dashpattern} + \O \S{predefined rgbcolor variable} + \O \S{predefined macro} + \O \S{tag} \S{suffix} +\StopSyntax + +\StartSyntax +\S{predefined numeric variable} + \M \FL{nothing yet} +\StopSyntax + +\StartSyntax +\S{predefined picture variable} + \M \FL{blankpicture} + \O \L{currentpicture} +\StopSyntax + +\StartSyntax +\S{predefined transform variable} + \M \L{identity} \O \L{currenttransform} +\StopSyntax + +\StartSyntax +\S{predefined path variable} + \M \FL{originpath} + \O \FL{fullcircle} \O \FL{fullsquare} \O \FL{fulldiamond} \O \FL{fulltriangle} + \O \FL{unitcircle} \O \FL{unitsquare} \O \FL{unitdiamond} \O \FL{unittriangle} + \O \FL{halfcircle} \O \FL{quartercircle} + \O \FL{llcircle} \O \FL{lrcircle} \O \FL{urcircle} \O \FL{ulcircle} + \O \FL{bcircle} \O \FL{tcircle} \O \FL{lcircle} \O \FL{rcircle} + \O \FL{triangle} + \O \FL{righttriangle} \O \FL{uptriangle} \O \FL{lefttriangle} \O \FL{downtriangle} + \O \FL{lltriangle} \O \FL{lrtriangle} \O \FL{urtriangle} \O \FL{ultriangle} + \O \L{cuttings} +\StopSyntax + +\StartSyntax +\S{predefined pair variable} + \M \L{right} \O \L{up} \O \L{left} \O \L{down} + \M \L{shadedright} \O \L{shadedup} \O \L{shadedleft} \O \L{shadeddown} +\StopSyntax + +\StartSyntax +\S{predefined pen variable} + \M \FL{pensquare} \O \FL{penrazor} \O \FL{penspec} + \O \L{currentpen} +\StopSyntax + +\StartSyntax +\S{predefined string variable} + \M \FL{EOF} + \O \FL{CRLF} \O \FL{crlf} + \O \FL{DQUOTE} \O \FL{dquote} \O \L{ditto} + \O \FL{SPACE} \O \FL{space} + \O \FL{PERCENT} \O \FL{percent} + \O \L{defaultfont} + \O \L{extra_beginfig} \O \L {extra_endfig} + \O \FL{pathconnectors} +\StopSyntax + +\StartSyntax +\S{predefined dashpattern} + \M \L{evenly} \O \FL{oddly} \O \L{withdots} +\StopSyntax + +\StartSyntax +\S{predefined rgbcolor variable} + \M \L{red} \O \L{green} \O \L{blue} \O \L{white} + \O \L{cyan} \O \L{magenta} \O \L{yellow} \O \L{black} + \O \L{background} + \O \FL{basiccolors} +\StopSyntax + +\StartSyntax +\S{predefined macro} + \M \FL{shipit} \O \FL{bye} + \O \FL{resetdrawoptions} + \O \FL{visualizepaths} \O \FL{naturalizepaths} +\StopSyntax + +\StartSyntax +\S{suffix} + \M \S{empty} + \O \S{suffix} \S{subscript} + \O \S{suffix} \S{tag} + \O \S{suffix parameter} +\StopSyntax + +\StartSyntax +\S{subscript} + \M \S{number} + \O \[ \S{numeric expression} \] +\StopSyntax + +\StartSyntax +\S{internal variable} + \M \L{ahangle} \O \L{ahlength} + \O \L{bboxmargin} \O \L{labeloffset} + \O \L{charcode} + \O \L{defaultcolormodel} \O \L{defaultpen} \O \L{defaultscale} + \O \L{linecap} \O \L{linejoin} \O \L{miterlimit} + \O \L{outputformat} \O \L{outputtemplate} \O \O \L{prologues} + \O \L{showstopping} \L{pausing} + \O \L{tracingoutput} \O \L{tracingcapsules} \O \L{tracingchoices} \O \L{tracingcommands} \O \L{tracingequations} + \O \L{tracinglostchars} \O \L{tracingmacros} \O \L{tracingonline} \O \L{tracingrestores} \O \L{tracingspecs} + \O \L{tracingstats} \O \L{tracingtitles} + \O \L{truecorners} \O \L{warningcheck} + \O \L{dotlabeldiam} + \O \L{day} \O \L{month} \O \L{year} \O \L{hour} \O \L{minute} \O \L{time} + \O \L{mm} \O \L{pt} \O \L{dd} \O \L{bp} \O \L{cm} \O \L{pc} \O \L{cc} \O \L{in} + \O \L{butt} \O \L{rounded} \O \L{squared} \O \L{mitered} \O \L{beveled} + \O \FL{pi} \O \FL{radian} \O \FL{eps} \O \FL{epsilon} + \O \FL{nocolormodel} \O \FL{greycolormodel} \O \FL{graycolormodel} \O \FL{rgbcolormodel} \O \FL{cmykcolormodel} + % \O \FL{shadefactor} + \O \FL{textextoffset} + \O \FL{maxdimensions} + \O \L{infinity} + \O \FL{charscale} + \O \FL{metapostversion} + \O \FL{normaltransparent} \O \FL{multiplytransparent} \O \FL{screentransparent} \O \FL{overlaytransparent} + \O \FL{softlighttransparent} \O \FL{hardlighttransparent} \O \FL{colordodgetransparent} \O \FL{colorburntransparent} + \O \FL{darkentransparent} \O \FL{lightentransparent} \O \FL{differencetransparent} \O \FL{exclusiontransparent} + \O \FL{huetransparent} \O \FL{saturationtransparent} \O \FL{colortransparent} \O \FL{luminositytransparent} + \O \S{symbolic token defined by \L{newinternal}} + \O \L{ahangle} \O \L{ahlength} + \O \L{bboxmargin} + \O \L{pen_bot} \O \L{pen_top} \O \L{pen_lft} \O \L{pen_rt} + \O \L{join_radius} + \O \L{crossingscale} \O \L{crossingoption} +\StopSyntax + +\StartSyntax +\S{pseudo function} + \M \L {min} \( \S{expression list} \)% + \O \L {max} \( \S{expression list} \) + \O \L {incr} \( \S{numeric variable} \)% + \O \L {decr} \( \S{numeric variable} \) + \O \L {dashpattern} \( \S{on/off list} \) + \O \L {interpath} \( \S{numeric expression} \L{,} \S{path expression} \L{,} \S{path expression} \) + \O \FL{interpolated} \( \S{numeric expression} \L{,} \S{path expression} \L{,} \S{path expression} \) + \O \L {buildcycle} \( \S{path expression list} \) + \O \L {thelabel} \S{label suffix} \( \S{expression} \L{,} \S{pair expression} \) + \O \FL{thefreelabel} \( \S{expression}\L{,} \S{pair expression} \L{,} \S{pair expression} \) + \O \FL{anglebetween} \( \S{path expression} \L{,} \S{path expression} \L{,} \S{expression} \) + \O \L {flex} \( \S{text} \) + \O \L {hide} \( \S{text} \) + \O \L {gobble} \S{primary} + \O \L {clearit} + \O \L {clearpen} + \O \L {clearxy} + \O \FL{pointarrow} \( \S{path expression} \L{,} \S{numeric or pair primary} \L{,} \S{numeric expression} \) + \O \FL{centerarrow} \( \S{path expression} \L{,} \S{numeric or pair primary} \L{,} \S{numeric expression} \) + \O \FL{leftarrow} \( \S{path expression} \L{,} \S{numeric or pair primary} \L{,} \S{numeric expression} \) + \O \FL{rightarrow} \( \S{path expression} \L{,} \S{numeric or pair primary} \L{,} \S{numeric expression} \) + \O \FL{paired} \( \S{numeric or pair} \)% + \O \FL{tripled} \( \S{numeric or color} \) + \O \FL{remappedcolor} \( \S{color expression} \) + \O \FL{superellipse} \( \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \L{,} \L{numeric primary} \L{,} \N \L{numeric primary} \) + \O \FL{roundedsquare} \( \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \) + \O \FL{tensecircle} \( \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \) + \O \FL{tensepath} \( \S{path primary} \) + \O \FL{(constructed)function}% + \( \S{string expression} \)% + \( \S{string primary} \L{,} \S{string primary} \L{,} \S{numeric primary} \L{,} + \N \S{numeric primary} \L{,} \S{numeric primary} \) + \O \FL{straightfunction} \( \S{string primary} \L{,} \S{string primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \L{,} + \N \S{numeric primary} \) + \O \FL{curvedfunction} \( \S{string primary} \L{,} \S{string primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \L{,} + \N \S{numeric primary} \) + %\O \FL{punkedfunction} \( \S{string primary} \L{,} \S{string primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \) + %\O \FL{tightfunction} \( \S{string primary} \L{,} \S{string primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \) + \O \FL{constructedpairs} \( \S{string expression} \) \( \S{pair array} \) + \O \FL{straightpairs} \( \S{pair array} \) + \O \FL{curvedpairs} \( \S{pair array} \) + %\O \FL{punkedpairs} \( \S{pair array} \) + %\O \FL{tightpairs} \( \S{pair array} \) + \O \FL{constructedpath} \( \S{string expression} \) \( \S{text} \) + \O \FL{straightpath} \( \S{text} \) + \O \FL{curvedpath} \( \S{text} \) + %\O \FL{punkedpath} \( \S{text} \) + %\O \FL{tightpath} \( \S{text} \) + \O \FL{epsed} \S{numeric primary} + \O \FL{arrowhead} \S{path primary} + \O \FL{arrowpath} \S{path primary} + \O \FL{infinite} \S{path primary} + % + \O \FL{tolist} \( \S{pair array} \) \( \S{text} \) + \O \FL{topath} \( \S{pair array} \) \( \S{text} \) + \O \FL{tocycle} \( \S{pair array} \) \( \S{text} \) + \O \FL{pencilled} \( \S{path expression} \) \( \S{pen expression} \) +\StopSyntax + +\StartSyntax +\S{color expression} + \M \S{basic color expression} + \O \S{string primary} + \O \FL{namedcolor} \( \S{string primary} \) + \O \FL{spotcolor} \( \S{string primary} \L{,} \S{basic color expression} \) + \O \FL{multitonecolor} \( \S{string primary} \L{,} \S{basic color expression list} \) +\StopSyntax + +\StartSyntax +\S{basic color expression} + \M \S{rgb color expression} + \O \S{cmyk color expression} + \O \S{gray color expression} +\StopSyntax + +\StartSyntax +\S{basic color expression list} + \M \S{basic color expression} + \O \S{basic color expression list} \L{,} \S{basic color expression} +\StopSyntax + +\StartSyntax +\S{rgb color expression} + \M \S\( \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \S\) +\StopSyntax + +\StartSyntax +\S{cmyk color expression} + \M \S\( \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{numeric primary} \S\) +\StopSyntax + +\StartSyntax +\S{gray color expression} + \M \S\( \S{numeric primary} \S\) + \O \S{numeric primary} +\StopSyntax + +\StartSyntax +\S{path expression list} + \M \S{path expression} + \O \S{path expression list} \L{,} \S{path expression} +\StopSyntax + +\StartSyntax +\S{on/off list} + \M \S{on/off list} \S{on/off clause} + \O \S{on/off clause} +\StopSyntax + +\StartSyntax +\S{on/off clause} + \M \L{on} \S{numeric tertiary} + \O \L{off} \S{numeric tertiary} +\StopSyntax + +\StartSyntax +\S{boolean expression} \M \S{expression} +\S{cmyk expression} \M \S{expression} +\S{color expression} \M \S{expression} +\S{numeric atom} \M \S{atom} +\S{numeric expression} \M \S{expression} +\S{numeric primary} \M \S{primary} +\S{numeric tertiary} \M \S{tertiary} +\S{numeric variable} \M \S{variable} \O \S{internal variable} +\S{pair expression} \M \S{expression} +\S{pair primary} \M \S{primary} +\S{path expression} \M \S{expression} +\S{path subexpression} \M \S{subexpression} +\S{pen expression} \M \S{expression} +\S{picture expression} \M \S{expression} +\S{picture variable} \M \S{variable} +\S{rgb expression} \M \S{expression} +\S{string expression} \M \S{expression} +\S{suffix parameter} \M \S{parameter} +\S{transform primary} \M \S{primary} +\StopSyntax + +\StartSyntax +\S{program} + \M \S{statement list} \L{end} +\StopSyntax + +\StartSyntax +\S{statement list} + \M \S{empty} + \O \S{statement list} \L{;} \S{statement} +\StopSyntax + +\StartSyntax +\S{statement} + \M \S{empty} + \O \S{equation} + \O \S{assignment} + \O \S{declaration} + \O \S{macro definition} + \O \S{compound} + \O \S{pseudo procedure} + \O \S{command} +\StopSyntax + +\StartSyntax +\S{compound} + \M \L{begingroup} \S{statement list} \L{endgroup} + \O \L{beginfig} \( \S{numeric expression} \) \L{;} \S{statement list} \S{;} \L{endfig} + \O \FL{beginglyph} \( \S{glyph property list} \) \L{;} \S{statement list} \S{;} \L{endglyph} + \O \L{image builder} \( \S{statement list} \) +\StopSyntax + +\StartSyntax +\S{image builder} + \M {image} \O \FL {decorated} \O \FL {redecorated} \O \FL {undecorated} +\StopSyntax + +\StartSyntax +\S{glyph property list} + \M \S{numeric expression} \L{,} \S{numeric expression} \L{,} \S{numeric expression} \L{,} \S{numeric expression} +\StopSyntax + +\StartSyntax +\S{equation} + \M \S{expression} \L{=} \S{right-hand side} +\StopSyntax + +\StartSyntax +\S{assignment} + \M \S{variable} \L{:=} \S{right-hand side} + \O \S{internal variable} \L{:=} \S{right-hand side} +\StopSyntax + +\StartSyntax +\S{right-and side} + \M \S{expression} + \O \S{equation} + \O \S{assignment} +\StopSyntax + +\StartSyntax +\S{declaration} + \M \S{type} \S{declaration list} +\StopSyntax + +\StartSyntax +\S{declaration list} + \M \S{generic variable} + \O \S{declaration list} \L{,} \S{generic variable} +\StopSyntax + +\StartSyntax +\S{generic variable} + \M \S{Symbolic token} \S{generic suffix} +\StopSyntax + +\StartSyntax +\S{generic suffix} + \M \S{empty} + \O \S{generic suffix} \S{tag} + \O \S{generic suffix} \L{[]} +\StopSyntax + +\StartSyntax +\S{macro definition} + \M \S{macro heading} \L{=} \S{replacement text} \L{enddef} +\StopSyntax + +\StartSyntax +\S{macro heading} + \M \L{def} \S{Symbolic token} \S{delimited part} \S{undelimited part} + \O \L{vardef} \S{generic variable} \S{delimited part} \S{undelimited part} + \O \L{vardef} \S{generic variable} \L{@#} \S{delimited part} \S{undelimited part} + \O \S{binary def} \S{parameter} \S {symbolic token} \S{parameter} +\StopSyntax + +\StartSyntax +\S{delimited part} + \M \S{empty} + \O \S{delimited part} \( \S{parameter type} \S{parameter tokens} \) +\StopSyntax + +\StartSyntax +\S{parameter type} + \M \L{expr} + \O \L{suffix} + \O \L{text} +\StopSyntax + +\StartSyntax +\S{parameter tokens} + \M \S{parameter} + \O \S{parameter tokens} \L{,} \S{parameter} +\StopSyntax + +\StartSyntax +\S{parameter} + \M \S{Symbolic token} +\StopSyntax + +\StartSyntax +\S{undelimited part} + \M \S{empty} + \O \S{parameter type} \S{parameter} + \O \S{precedence level} \S{parameter} + \O \L{expr} \S{parameter} \L{of} \S{parameter} +\StopSyntax + +\StartSyntax +\S{precedence level} + \M \L{primary} + \O \L{secondary} + \O \L{tertiary} +\StopSyntax + +\StartSyntax +\S{binary def} + \M \S{primarydef} + \O \S{secondarydef} + \O \S{tertiarydef} +\StopSyntax + +\StartSyntax +\S{pseudo procedure} + \M \L {drawoptions} \( \S{option list} \) + \O \L {label} \S{label suffix} \( \S{expression} \L{,} \S{pair expression} \) + \O \L {thelabel} \S{label suffix} \( \S{expression} \L{,} \S{pair expression} \) + \O \L {dotlabel} \S{label suffix} \( \S{expression} \L{,} \S{pair expression} \) + \O \L {makelabel} \S{makelabel} + \O \L {labels} \S{label suffix} \( \S{point number list} \) + \O \L {dotlabels} \S{label suffix} \( \S{point number list} \) + \O \FL{textext} \S{label suffix} \( \S{expression} \) + \O \FL{infotext} \S{label suffix} \( \S{expression}, \S{numeric expression} \) + \O \FL{thetextext} \S{label suffix} \( \S{expression}, \S{pair expression} \) + \O \FL{rawtextext} \( \S{expression} \) + \O \FL{verbatim} \S{string expression} + \O \FL{freelabel} \( \S{expression} \L{,} \S{pair expression} \L{,} \S{pair expression} \) + \O \FL{freedotlabel} \( \S{expression} \L{,} \S{pair expression} \L{,} \S{pair expression} \) + \O \FL{remapcolor} \( \S{color expression} \L{,} \S{color expression} \) + \O \FL{resetcolormap} + \O \FL{recolor} \S{picture expression} + \O \FL{bitmapimage} \( \S{numeric primary} \L{,} \S{numeric primary} \L{,} \S{string primary} \) + \O \FL{pushboundingbox} \O \FL{popboundingbox} + \O \FL{pushcurrentpicture} \O \FL{popcurrentpicture} + \O \FL{externalfigure} \S{string expression} \S{transformer} + \O \FL{loadfigure} \S{string expression} \L{number} \S{numeric expression} \S{transformer} + \O \FL{properties} + \O \L {anchored} \S{label suffix} \( \S{expression} \L{,} \S{pair expression} \) +\StopSyntax + +\StartSyntax +\S{point number list} + \M \S{suffix} \O \S{point number list} \L{,} \S{suffix} +\StopSyntax + +\StartSyntax +\S{label suffix} + \M \S{empty} + \O \L{lft} \O \L{rt}\O \L{top} \O \L{bot} \O \L{ulft} \O \L{urt}% + \O \L{llft} \O \L{lrt} \O \FL{raw} \O \FL{origin} +\StopSyntax + +\StartSyntax +\S{command} + \M \L{clip} \S{picture variable} \L{to} \S{path expression} + \O \L{interim} \S{internal variable} \L{:=} \S{right-hand side} + \O \L{let} \S{symbolic token} \L{=} \S{symbolic token} + \O \L{pickup} \S{expression} + \O \L{randomseed} \L{:=} \S{numeric expression} + \O \L{save} \S{symbolic token list} + \O \L{delimiters} \S{character} \S{character} + \O \L{setbounds} \S{picture variable} \L{to} \S{path expression} + \O \L{shipout} \S{picture expression} + \O \L{special} \S{string expression} + \O \L{endinput} + \O \L{expandafter} + \O \S{addto command} + \O \S{drawing command} + \O \S{font metric command} + \O \S{newinternal command} + \O \S{message command} + \O \S{mode command} + \O \S{show command} + \O \S{special command} + \O \S{tracing command} + \O \S{scantokens} \S{string expression} + \O \FL{defineshade} \S{symbolic token} \S{shading expression} + \O \L{write} \S{string expression} \L{to} \S{string expression} + \O \L{readfrom} \S{string expression} + \O \FL{readfile} \S{string expression} + \O \L{readstring} + \O \L{restoreclipcolor} + \O \L{savepen} + \O \L{runscript} + \O \L{relax} +\StopSyntax + +\StartSyntax +\S{show command} + \M \L{show} \S{expression list} + \O \L{showvariable} \S{symbolic token list} + \O \L{showtoken} \S{symbolic token list} + \O \L{showdependencies} +\StopSyntax + +\StartSyntax +\S{symbolic token list} + \M \S{symbolic token} + \O \S{symbolic token} \L{,} \S{symbolic token list} +\StopSyntax + +\StartSyntax +\S{expression list} + \M \S{expression} + \O \S{expression list} \L{,} \S{expression} +\StopSyntax + +\StartSyntax +\S{addto command} + \M \L{addto} \S{picture variable} \L{also} \S{picture expression} \S{option list} + \O \L{addto} \S{picture variable} \L{contour} \S{path expression} \S{option list} + \O \L{addto} \S{picture variable} \L{doublepath} \S{path expression} \S{option list} +\StopSyntax + +\StartSyntax +\S{option list} + \M \S{empty} + \O \S{drawing option} \S{option list} +\StopSyntax + +\StartSyntax +\S{drawing option} + \M \L {withcolor} \S{color expression}% + \O \FL {withgrey} \S{numeric expression}% + \O \FL {withgray} \S{numeric expression} + \O \L {withrgbcolor} \S{rgb expression}% + \O \L {withcmykcolor} \S{cmyk expression}% + \O \L {withgreyscale} \S{numeric expression} + \O \L {withoutcolor} + \O \L {withprescript} \S{string expression}% + \O \L {withpostscript} \S{string expression} + \O \L {withpen} \S{pen expression} + \O \L {dashed} \S{picture expression} + \O \FL{undashed} + \O \FL{withshade} \S{numeric expression} \O \FL{shaded} \S{shading expression} + \O \FL{withproperties} \S{property primary} + \O \FL{withtransparency} \S{pair primary} + \O \FL{withlinearshade} \(% + \S{path expression} \L{,}% + \S{path expression} \L{,}% + \S{color expression} \L{,}% + \S{color expression} \) + \O \FL{withcircularshade} \(% + \S{path ex} \L{,}% + \S{path ex} \L{,}% + \S{numeric ex} \L{,}% + \S{numeric ex} \L{,}% + \S{color ex} \L{,}% + \S{color ex} \) + \O \S{shading expression} + \O \FL{onlayer} \S{string expression} + \O \FL{withmask} \S{string expression} +\StopSyntax + +\StartSyntax +\S{property expression} + \M \( {drawing option} \) +\StopSyntax + +\StartSyntax +\S{shading expression} + \M \FL{withshademethod} \L{string expression} + \O \FL{withshadefactor} \L{numeric expression} + \O \FL{withshadedomain} \L{pair expression} + \O \FL{withshadevector} \L{pair expression} + \O \FL{withshaderadius} \L{pair expression} + \O \FL{withshadeorigin} \L{pair expression} + \O \FL{withshadecolors} \( \S{color expression} \L{,} \S{color expression} \) + \O \FL{withshadecenter} \L{pair expression} +\StopSyntax + +\StartSyntax +\S{drawing command} + \M \L{draw} \S{picture expression} \S{option list} + \O \S{fill type} \S{path expression} \S{option list} +\StopSyntax + +\StartSyntax +\S{fill type} + \M \L {fill} \O \L{unfill} \O \FL{refill} + \O \L {draw} \O \L{undraw} \O \FL{redraw} + \O \L {filldraw} \O \FL{drawfill} \O \L{undrawfill} \O \L{unfilldraw} + \O \FL{eofill} \O \FL{nofill} \O \FL{fillup} + \O \L {drawdot} + \O \L {drawarrow} \O \L{drawdblarrow} + \O \L {cutdraw} + \O \L {visualizer} + \O \FL{normaldraw} \O \FL{normalfill} +\StopSyntax + +\StartSyntax +\S{visualizer} + \M \FL{drawboundary} \O \FL{drawboundingbox} \O \FL{drawboundoptions} + \O \FL{drawcontrollines} \O \FL{drawcontroloptions} \O \FL{drawcontrolpoints} + \O \FL{drawlabeloptions} \O \FL{drawlineoptions} \O \FL{drawoptions} + \O \FL{draworigin} \O \FL{draworiginoptions} + \O \FL{drawpath} \O \FL{drawpathoptions} + \O \FL{drawpoint} \O \FL{drawpointlabels} \O \FL{drawpointoptions} + \O \FL{drawpoints} \O \FL{drawwholepath} + \O \FL{visualizeddraw} \O \FL{visualizedfill} +\StopSyntax + +\StartSyntax +\S{newinternal command} + \M \L{newinternal} \S{internal type} \S{symbolic token list} + \O \S{newinternal} \S{symbolic token list} +\StopSyntax + +\StartSyntax +\S{message command} + \M \L{errhelp} \S{string expression} + \O \L{errmessage} \S{string expression} + \O \L{filenametemplate} \S{string expression} + \O \L{message} \S{string expression} +\StopSyntax + +\StartSyntax +\S{mode command} + \M \L{batchmode} + \O \L{nonstopmode} + \O \L{scrollmode} + \O \L{errorstopmode} + \O \L{interact} +\StopSyntax + +\StartSyntax +\S{special command} + \M \L{fontmapfile} \S{string expression} + \O \L{fontmapline} \S{string expression} + \O \L{special} \S{string expression} + \O \L{input} \S{string expression} + \O \L{prologies} \S{numeric expression} + \O \L{outputtemplate} \S{string expression} + \O \L{outputformat} \S{string expression} +\StopSyntax + +\StartSyntax +\S{tracing command} + \M \L{tracingall} + \O \L{loggingall} + \O \L{tracingnone} +\StopSyntax + +\StartSyntax +\S{if test} + \M \L{if} \S{boolean expression} \L{:} \S{balanced tokens} \S{alternatives} \L{fi} +\StopSyntax + +\StartSyntax +\S{alternatives} + \M \S{empty} + \O \L{else} \L{:} \S{balanced tokens} + \O \L{elseif} \S{boolean expression} \S{:} \S{balanced tokens} \S{alternatives} + \O \L{exit} \O \L{exitif} \S{boolean expression} \O \L{exitunless} \S{boolean expression} + \O \L{break} +\StopSyntax + +\StartSyntax +\S{loop} + \M \S{loop header} \L{:} \S{loop text} \L{endfor} +\StopSyntax + +\StartSyntax +\S{loop header} + \M \L{for} \S{symbolic token} \L{=} \S{progression} + \O \L{for} \S{symbolic token} \L{=} \S{for list} + \O \L{for} \S{symbolic token} \L{within} \S{picture expression} + \O \L{forsuffixes} \S{symbolic token} \L{=} \S{suffix list} + \O \L{forever} +\StopSyntax + +\StartSyntax +\S{progression} + \M \S{numeric expression} \L{upto} \S{numeric expression} + \O \S{numeric expression} \L{downto} \S{numeric expression} + \O \S{numeric expression} \L{step} \S{numeric expression} \L{until} \S{numeric expression} + \O \L{range} \S{numeric expression} \L{thru} \S{numeric expression} +\StopSyntax + +\StartSyntax +\S{for list} + \M \S{expression} + \O \S{for list} \L{,} \S{expression} +\StopSyntax + +\StartSyntax +\S{suffix list} + \M \S{suffix} + \O \S{suffix list} \L{,} \S{suffix} +\StopSyntax + +\stop + +% \stopsection + +\stopchapter + +\stopcomponent + +% \startsection[title={Left overs}] + +% There are a few more concepts and commands available in \METAFUN, like color +% remapping, shading and graphic inclusion. Because they have their own small +% syntax world, we present them here. +% +% You may consider shades to be internally represented by a hidden datastructure. +% The end user has access to a shade by means of a pointer, expressed in a numeric. +% +% \start \switchtobodyfont[small] +% +% \StartSyntax +% \S{pseudo procedure} +% \M \FL{linear_shade}% +% \( \S{path expression} \L{,} \S{numeric expression}% +% \L{,} \S{color expression} \L{,} \S{color expression} \) +% \O \FL{circular_shade}% +% \( \S{path expression} \L{,} \S{numeric expression}% +% \L{,} \S{color expression} \L{,} \S{color expression} \) +% \StopSyntax +% +% \StartSyntax +% \S{pseudo function} +% \M \FL{define_linear_shade}% +% \( \S{pair expr} \L{,} \S{pair expr}% +% \L{,} \S{color expr} \L{,} \S{color expr} \) +% \O \FL{define_circular_shade}% +% \( \S{pair expr} \L{,} \S{pair expr}% +% \L{,} \S{path expr} \L{,} \S{path expr}% +% \L{,} \S{color expr} \L{,} \S{color expr} \) +% \O \FL{predefined_linear_shade}% +% \( \S{path expr} \L{,} \S{numeric expr}% +% \L{,} \S{color expr} \L{,} \S{color expr} \) +% \O \FL{predefined_circular_shade}% +% \( \S{path expr} \L{,} \S{numeric expr}% +% \L{,} \S{color expr} \L{,} \S{color expr} \) +% \StopSyntax +% +% \stop + +% External figures are just files, so the string passed as first argument needs to +% be a valid filename. Additionally, they need to be given dimensions. + +% \start \switchtobodyfont[small] +% +% \StartSyntax +% \S{pseudo procedure} +% \M \FL{externalfigure} \S{string expression} \S{transformer} +% \StopSyntax +% +% \stop + +% An external \METAPOST\ graphic can be loaded by filename and figure number. The +% normal transformations can be applied. +% +% \start \switchtobodyfont[small] +% +% \StartSyntax +% \S{pseudo procedure} +% \M \FL{loadfigure} \S{string expression} \L{number} \S{numeric expression} \S{transformer} +% \StopSyntax +% +% \stop + +% A graphic text is (normally) an outline representation of a snippet of text +% typeset by \TEX. This procedure has a couple of dedicated options. + +% \start \switchtobodyfont[small] + +% \StartSyntax +% \S{pseudo procedure} +% \M \FL{graphictext} \S{string expression} \S{transformer} \S{text option list} +% \O \FL{regraphictext} \S{transformer} \S{text option list} +% \StopSyntax + +% \StartSyntax +% \S{text option list} +% \M \S{empty} +% \O \S{text drawing option} \S{text option list} +% \StopSyntax + +% \StartSyntax +% \S{text drawing option} +% \M \S{drawing option} +% \O \FL{reversefill} +% \O \FL{outlinefill} +% \O \FL{withdrawcolor} \S{color expression} +% \O \FL{withfillcolor} \S{color expression} +% \StopSyntax + +% \StartSyntax +% \S{pseudo procedure} +% \M \FL{resetgraphictextdirective} +% \O \FL{graphictextdirective} \S {string expression} +% \StopSyntax + +% \StartSyntax +% \S{internal variable} +% \M \FL{graphictextformat} +% \StopSyntax + +% \stop + +% \stopsection + +% \stopchapter + +% \stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-text.tex b/doc/context/sources/general/manuals/metafun/metafun-text.tex new file mode 100644 index 000000000..f70f53ac3 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-text.tex @@ -0,0 +1,1784 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\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 loadint 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} to \typ {\startMPenvironment}. + +\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 \type {\startMPdrawing} 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. + +\input meta-imp-txt.mkiv % we need to force a reload \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} + baselineskip := 8pt ; + strutheight := (7.2/10) * baselineskip ; + strutdepth := (2.8/10) * baselineskip ; + offset := baselineskip/2 ; + topskip := 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-2offset)/hsize) + yscaled ((vsize-2offset)/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 {topskip}, 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,-topskip) ; + 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=topskip step baselineskip 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<baselineskip) : + vvsize := vsize ; + else : + vvsize := (vsize div baselineskip) * baselineskip ; + fi ; + + for i=topskip step baselineskip 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} +baselineskip := 8pt ; +strutheight := 4pt ; +strutdepth := 2pt ; +offset := 4pt ; +topskip := 3pt ; +\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, offset, baselineskip, + strutheight, strutdepth, topskip) = + + \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<baselineskip) : + vvsize := vsize ; + else : + vvsize := (vsize div baselineskip) * baselineskip ; + fi ; + + for i=topskip step baselineskip 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*\baselinedistance, % offset + \baselinedistance, % 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} + +% \blank{\em todo: mp data file}\blank +% \writestatus{!!!!}{todo: mp data file} + +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} + +The macro discussed in the previous section is included in one of the \METAPOST\ +libraries, so we first have to say: + +\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 (topskip 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,\baselinedistance, + \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,\baselinedistance, + \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,\baselinedistance, + \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,\baselinedistance, + \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 +\setupframed + [offset=overlay,align=normal,frame=off, + width=\parwidth,height=\parheight] +\startcombination[2*2] + {\framed[background=test 1]{\getshapetext}} {test 1} + {\framed[background=test 2]{\getshapetext}} {test 2} + {\framed[background=test 3]{\getshapetext}} {test 3} + {\framed[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,\baselinedistance, + \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 diff --git a/doc/context/sources/general/manuals/metafun/metafun-titlepage-paper.tex b/doc/context/sources/general/manuals/metafun/metafun-titlepage-paper.tex new file mode 100644 index 000000000..558e3b798 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-titlepage-paper.tex @@ -0,0 +1,23 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\doifmode{book}{\endinput} + +\startcomponent mfun-titlepage-paper + +\environment metafun-environment + +\setupbackgrounds + [rightpage] + [background=title page] + +\startstandardmakeup + % title page +\stopstandardmakeup + +\setupbackgrounds + [rightpage] + [background=] + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-titlepage-screen.tex b/doc/context/sources/general/manuals/metafun/metafun-titlepage-screen.tex new file mode 100644 index 000000000..6350bdbda --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-titlepage-screen.tex @@ -0,0 +1,30 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-titlepage-screen + +\environment metafun-environment + +\startstandardmakeup[topstate=empty] + + \definefont[Big] [RegularBold*default at 60pt] + \definefont[Medium][RegularBold*default at 48pt] + \definefont[Small] [RegularBold*default at 32pt] + \definefont[Tiny] [RegularBold*default at 24pt] + +% \showstruts + + \startcolor[darkyellow] + + \Big METAFUN \par + \Tiny \setstrut \strut context mkiv \par + \vfill + \Tiny \setstrut \hfill \strut \currentdate \par + \Small \setstrut \hfill \strut Hans Hagen \par + + \stopcolor + +\stopstandardmakeup + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun-welcome.tex b/doc/context/sources/general/manuals/metafun/metafun-welcome.tex new file mode 100644 index 000000000..425d15796 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun-welcome.tex @@ -0,0 +1,3502 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent metafun-welcome + +\environment metafun-environment + +\startchapter[reference=sec:welcome,title={Welcome to MetaPost}] + +\startintro + +In this chapter, we will introduce the most important \METAPOST\ concepts as well +as demonstrate some drawing primitives and operators. This chapter does not +replace the \METAFONT\ book or \METAPOST\ manual, both of which provide a lot of +explanations, examples, and (dirty) tricks. + +As its title says, the \METAFONT\ book by Donald.\ E.\ Knuth is about fonts. +Nevertheless, buying a copy is worth the money, because as a \METAPOST\ user you +can benefit from the excellent chapters about curves, algebraic expressions, and +(linear) equations. The following sections are incomplete in many aspects. More +details on how to define your own macros can be found in both the \METAFONT\ book +and \METAPOST\ manual, but you will probably only appreciate the nasty details if +you have written a few simple figures yourself. This chapter will give you a +start. + +A whole section is dedicated to the basic extensions to \METAPOST\ as provided by +\METAFUN. Most of them are meant to make defining graphics like those shown in +this document more convenient. + +Many of the concepts introduced here will be discussed in more detail in later +chapters. So, you may consider this chapter to be an appetizer for the following +chapters. If you want to get started quickly, you can safely skip this chapter +now. + +\stopintro + +\startsection[title={Paths}] + +\index{paths} + +Paths are the building blocks of \METAPOST\ graphics. In its simplest form, a +path is a single point. + +\startuseMPgraphic{axis} + tickstep := 1cm ; ticklength := 2mm ; + drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ; + tickstep := tickstep/2 ; ticklength := ticklength/2 ; + drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ; +\stopuseMPgraphic + +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + drawpoint "1cm,1.5cm" ; +\stopMPcode +\stoplinecorrection + +Such a point is identified by two numbers, which represent the horizontal and +vertical position, often referred to as $x$ and $y$, or $(x,y)$. Because there +are two numbers involved, in \METAPOST\ this point is called a pair. Its related +datatype is therefore \type {pair}. The following statements assigns the point we +showed previously to a pair variable. + +\starttyping +pair somepoint ; somepoint := (1cm,1.5cm) ; +\stoptyping + +A pair can be used to identify a point in the two dimensional coordinate space, +but it can also be used to denote a vector (being a direction or displacement). +For instance, \type {(0,1)} means \quote {go up}. Looking through math glasses, +you may consider them vectors, and if you know how to deal with them, \METAPOST\ +may be your friend, since it knows how to manipulate them. + +You can connect points and the result is called a path. A path is a straight or +bent line, and is not necessarily a smooth curve. An example of a simple +rectangular path is: \footnote {In the next examples we use the debugging +features discussed in \in {chapter} [sec:debugging] to visualize the points, +paths and bounding boxes.} + +\startuseMPgraphic{path} + path p ; + p := unitsquare xyscaled (2cm,1cm) shifted (.5cm,.5cm) ; +\stopuseMPgraphic + +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + drawpath p ; +\stopMPcode +\stoplinecorrection + +This path is constructed out of four points: + +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + swappointlabels := true ; drawpath p ; drawpoints p ; +\stopMPcode +\stoplinecorrection + +Such a path has both a beginning and end and runs in a certain direction: + +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + autoarrows := true ; + swappointlabels := true ; drawarrowpath p ; drawpoints p ; +\stopMPcode +\stoplinecorrection + +A path can be open or closed. The previous path is an example of a closed path. +An open path looks like this: + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,1.5cm)..(2cm,0cm) ; +\stopuseMPgraphic + +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + swappointlabels := true ; drawpath p ; drawpoints p ; +\stopMPcode +\stoplinecorrection + +When we close this path |<|and in a moment we will see how to do this|>| the path +looks like: + +\startbuffer +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + p := p .. cycle ; + swappointlabels := true ; drawpath p ; drawpoints p ; +\stopMPcode +\stoplinecorrection +\stopbuffer + +\getbuffer + +The open path is defined as: + +\starttyping +(1cm,1cm)..(1.5cm,1.5cm)..(2cm,0cm) +\stoptyping + +The \quote {double period} connector \type {..} tells \METAPOST\ that we want to +connect the lines by a smooth curve. If you want to connect points with straight +line segments, you should use \type {--}. + +Closing the path is done by connecting the first and last point, using the \type +{cycle} command. + +\starttyping +(1cm,1cm)..(1.5cm,1.5cm)..(2cm,0cm)..cycle +\stoptyping + +Feel free to use \type {..} or \type {--} at any point in your path. + +\starttyping +(1cm,1cm)--(1.5cm,1.5cm)..(2cm,0cm)..cycle +\stoptyping + +\startuseMPgraphic{path} +path p ; p := (1cm,1cm)--(1.5cm,1.5cm)..(2cm,0cm)..cycle ; +\stopuseMPgraphic + +This path, when drawn, looks like this: + +\getbuffer + +As you can see in some of the previous examples, \METAPOST\ is capable of drawing +a smooth curve through the three points that make up the path. We will now +examine how this is done. + +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + p := p .. cycle ; swappointlabels := true ; + drawpath p ; drawcontrollines p ; drawpoints p ; drawcontrolpoints p ; +\stopMPcode +\stoplinecorrection + +The six small points are the so called control points. These points pull their +parent point in a certain direction. The further away such a point is, the +stronger the pull. + +Each point has at most two control points. As you can see in the following +graphic, the endpoints of a non closed curve have only one control point. + +\startuseMPgraphic{path} +path p ; p := (1.5cm,1.5cm)..(2cm,0cm)..(1cm,1cm) ; +\stopuseMPgraphic + +\startbuffer[path] +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + swappointlabels := true ; + drawpath p ; drawcontrollines p ; drawpoints p ; drawcontrolpoints p ; +\stopMPcode +\stoplinecorrection +\stopbuffer + +\getbuffer[path] + +This time we used the path: + +\starttyping +(1.5cm,1.5cm)..(2cm,0cm)..(1cm,1cm) +\stoptyping + +When you connect points by a smooth curve, \METAPOST\ will calculate the control +points itself, unless you specify one or more of them. + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,1.5cm)..controls (3cm,2cm)..(2cm,0cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +This path is specified as: + +\starttyping +(1cm,1cm)..(1.5cm,1.5cm)..controls (3cm,2cm)..(2cm,0cm) +\stoptyping + +In this path, the second and third point share a control point. Watch how the +curve is pulled in that direction. It is possible to pull a bit less by choosing +a different control point: + +\starttyping +(1cm,1cm)..(1.5cm,1.5cm)..controls (2.75cm,1.25cm)..(2cm,0cm) +\stoptyping + +Now we get: + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,1.5cm)..controls (2.75cm,1.25cm)..(2cm,0cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +We can also specify a different control point for each connecting segment. + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..controls (.5cm,2cm) and (2.5cm,2cm)..(2cm,.5cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +This path is defined as: + +\starttyping +(1cm,1cm)..controls (.5cm,2cm) and (2.5cm,2cm)..(2cm,.5cm) +\stoptyping + +\stopsection + +\startsection[title={Transformations}] + +\index{transformations} + +We can store a path in a path variable. Before we can use such a variable, we +have to allocate its memory slot with \type {path}. + +\starttyping +path p ; p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm) ; +\stoptyping + +Although we can manipulate any path in the same way, using a variable saves us +the effort to key in a path more than once. + +\startuseMPgraphic{axis} + tickstep := 1cm ; ticklength := 2mm ; + drawticks unitsquare xscaled 8cm yscaled 4cm ; + tickstep := tickstep/2 ; ticklength := ticklength/2 ; + drawticks unitsquare xscaled 8cm yscaled 4cm ; +\stopuseMPgraphic + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm)..cycle ; + path q ; q := p shifted (4cm,2cm) ; +\stopuseMPgraphic + +\startbuffer[path] +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + swappointlabels := true ; + drawpath p ; drawcontrollines p ; drawpoints p ; drawcontrolpoints p ; + drawpath q ; drawcontrollines q ; drawpoints q ; drawcontrolpoints q ; +\stopMPcode +\stoplinecorrection +\stopbuffer + +\getbuffer[path] + +In this graphic, the path stored in \type {p} is drawn twice, once in its +displaced form. The displacement is defined as: + +\starttyping +p shifted (4cm,2cm) +\stoptyping + +In a similar fashion you can rotate a path. You can even combine shifts and +rotations. First we rotate the path 15 degrees counter||clockwise around the +origin. + +\starttyping +p rotated 15 +\stoptyping + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm)..cycle ; + path q ; q := p rotated 15 ; +\stopuseMPgraphic + +\getbuffer[path] + +This rotation becomes more visible when we also shift the path to the right by +saying: + +\starttyping +rotated 15 shifted (4cm,0cm) +\stoptyping + +Now we get: + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm)..cycle ; + path q ; q := p rotated 15 shifted (4cm,0cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +Note that \type {rotated 15} is equivalent to \typ {p rotatedaround (origin, +15)}. + +It may make more sense to rotate the shape around its center. This can easily be +achieved with the \type {rotatedaround} command. Again, we move the path to the +right afterwards. + +\starttyping +p rotatedaround(center p, 15) shifted (4cm,0cm) +\stoptyping + +\startuseMPgraphic{axis} + tickstep := 1cm ; ticklength := 2mm ; + drawticks unitsquare xscaled 10cm yscaled 3cm ; + tickstep := tickstep/2 ; ticklength := ticklength/2 ; + drawticks unitsquare xscaled 10cm yscaled 3cm ; +\stopuseMPgraphic + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm)..cycle ; + path q ; q := p rotatedaround(center p, 15) shifted (4cm,0cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +Yet another transformation is slanting. Just like characters can be upright or +slanted, a graphic can be: + +\starttyping +p slanted 1.5 shifted (4cm,0cm) +\stoptyping + +\startuseMPgraphic{path} + path p ; p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm)..cycle ; + path q ; q := p slanted 1.5 shifted (4cm,0cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +The slant operation's main application is in tilting fonts. The $x$||coodinates +are increased by a percentage of their $y$||coordinate, so here every $x$ becomes +$x+1.5y$. The $y$||coordinate is left untouched. The following table summarizes +the most important primitive transformations that \METAPOST\ supports. + +\starttabulate[|lT|l|] +\HL +\NC \METAPOST\ code \NC mathematical equivalent \NC \NR +\HL +\NC (x,y) shifted (a,b) \NC $(x+a,y+b)$ \NC \NR +\NC (x,y) scaled s \NC $(sx,sy)$ \NC \NR +\NC (x,y) xscaled s \NC $(sx,y)$ \NC \NR +\NC (x,y) yscaled s \NC $(x,sy)$ \NC \NR +\NC (x,y) zscaled (u,v) \NC $(xu-yv,xv+yu)$ \NC \NR +\NC (x,y) slanted s \NC $(x+sy,y)$ \NC \NR +\NC (x,y) rotated r \NC $(x\cos(r)-y\sin(r),x\sin(r)+y\cos(r))$ \NC \NR +\HL +\stoptabulate + +The previously mentioned \type {rotatedaround} is not a primitive but a macro, +defined in terms of shifts and rotations. Another transformation macro is +mirroring, or in \METAPOST\ terminology, \type {reflectedabout}. + +\startbuffer[path] +\startlinecorrection[blank] +\startMPcode + \includeMPgraphic{axis} + \includeMPgraphic{path} + swappointlabels := true ; + drawpath p ; drawpoints p ; + drawpath q ; drawpoints q ; +\stopMPcode +\stoplinecorrection +\stopbuffer + +\startuseMPgraphic{path} + path p ; p := unitsquare scaled 2cm shifted (2cm,.5cm) ; + path q ; q := unitsquare scaled 2cm shifted (2cm,.5cm) reflectedabout((2.4cm,-.5),(2.4cm,3cm)) ; + draw (2.4cm,-.5cm)--(2.4cm,3cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +The reflection axis is specified by a pair of points. For example, in the graphic +above, we used the following command to reflect the square about a line through +the given points. + +\starttyping +p reflectedabout((2.4cm,-.5),(2.4cm,3cm)) +\stoptyping + +The line about which the path is mirrored. Mirroring does not have to be parallel +to an axis. + +\starttyping +p reflectedabout((2.4cm,-.5),(2.6cm,3cm)) +\stoptyping + +The rectangle now becomes: + +\startuseMPgraphic{path} + path p ; p := unitsquare scaled 2cm shifted (2cm,.5cm) ; + path q ; q := unitsquare scaled 2cm shifted (2cm,.5cm) reflectedabout((2.4cm,-.5),(2.6cm,3cm)) ; + draw (2.4cm,-.5cm)--(2.6cm,3cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +\pagereference [zscaled]The table also mentions \type {zscaled}. + +\startuseMPgraphic{path} +path p ; p := unitsquare scaled (1cm) shifted (1cm,.5cm) ; +path q ; q := unitsquare scaled (1cm) zscaled (2,.5) shifted (1cm,.5cm) ; +\stopuseMPgraphic + +\getbuffer[path] + +A \type {zscaled} specification takes a vector as argument: + +\starttyping +p zscaled (2,.5) +\stoptyping + +The result looks like a combination of scaling and rotation, and conforms to the +formula in the previous table. + +Transformations can be defined in terms of a transform matrix. Such a matrix is +stored in a transform variable. For example: + +\starttyping +transform t ; t := identity scaled 2cm shifted (4cm,1cm) ; +\stoptyping + +We use the associated keyword \type {transformed} to apply this matrix to a path +or picture. + +\starttyping +p transformed t +\stoptyping + +In this example we've taken the \type {identity} matrix as starting point but you +can use any predefined transformation. The identity matrix is defined in such a +way that it scales by a factor of one in both directions and shifts over the +zero||vector. + +Transform variables can save quite some typing and may help you to force +consistency when many similar transformations are to be done. Instead of changing +the scaling, shifting and other transformations you can then stick to just +changing the one transform variable. + +\stopsection + +\startsection[title={Constructing paths}] + +\index{paths} + +In most cases, a path will have more points than the few shown here. Take for +instance a so called {\em super ellipse}. + +\startlinecorrection[blank] +\startMPcode +path p ; p := fullsquare xyscaled (5cm,3cm) superellipsed .85 ; +drawpath p ; drawpoints p ; +visualizepaths ; draw p shifted (6cm,0cm) withcolor .625yellow ; +\stopMPcode +\stoplinecorrection + +These graphics provide a lot of information. In this picture the crosshair in the +center is the {\em origin} and the dashed rectangle is the {\em bounding box} of +the super ellipse. The bounding box specifies the position of the graphic in +relation to the origin as well as its width and height. + +In the graphic on the right, you can see the points that make up the closed path +as well as the control points. Each point has a number with the first point +numbered zero. Because the path is closed, the first and last point coincide. + +\startuseMPgraphic{axis} + tickstep := 1cm ; ticklength := 2mm ; + drawticks unitsquare xscaled 8cm yscaled 3cm ; + tickstep := tickstep/2 ; ticklength := ticklength/2 ; + drawticks unitsquare xscaled 8cm yscaled 3cm ; +\stopuseMPgraphic + +\startbuffer +\startlinecorrection[blank] +\startMPcode + string tmp ; defaultfont := "\truefontname{Mono}" ; + \includeMPgraphic{axis} + \includeMPgraphic{points} + \includeMPgraphic{path} + label.lft(verbatim(tmp),(14.5cm,2.5cm)) ; + drawwholepath scantokens(tmp) ; +\stopMPcode +\stoplinecorrection +\stopbuffer + +We've used the commands \type {..} and \type {--} as path connecting directives. +In the next series of examples, we will demonstrate a few more. However, before +doing that, we define a few points, using the predefined \type {z} variables. + +\startuseMPgraphic{points} + z0 = (0.5cm,1.5cm) ; z1 = (2.5cm,2.5cm) ; + z2 = (6.5cm,0.5cm) ; z3 = (3.0cm,1.5cm) ; +\stopuseMPgraphic + +\starttyping +z0 = (0.5cm,1.5cm) ; z1 = (2.5cm,2.5cm) ; +z2 = (6.5cm,0.5cm) ; z3 = (3.0cm,1.5cm) ; +\stoptyping + +Here \type {z1} is a short way of saying \type {(x1,y1)}. When a \type {z} +variable is called, the corresponding \type {x} and \type {y} variables are +available too. Later we will discuss \METAPOST\ capability to deal with +expressions, which are expressed using an \type {=} instead of \type {:=}. In +this case the expression related to \type {z0} is expanded into: + +\starttyping +z0 = (x0,y0) = (0.5cm,1.5cm) ; +\stoptyping + +But for this moment let's forget about their expressive nature and simply see +them as points which we will now connect by straight line segments. + +\startuseMPgraphic{path} + tmp := "z0--z1--z2--z3--cycle" ; +\stopuseMPgraphic + +\getbuffer + +The smooth curved connection, using \type {..} looks like: + +\startuseMPgraphic{path} + tmp := "z0..z1..z2..z3..cycle" ; +\stopuseMPgraphic + +\getbuffer + +If we replace the \type {..} by \type {...}, we get a tighter path. + +\startuseMPgraphic{path} + tmp := "z0...z1...z2...z3...cycle" ; +\stopuseMPgraphic + +\getbuffer + +Since there are \type {..}, \type {--}, and \type {...}, it will be no surprise +that there is also \type {---}. + +\startuseMPgraphic{path} + tmp := "z0---z1---z2---z3---cycle" ; +\stopuseMPgraphic + +\getbuffer + +If you compare this graphic with the one using \type {--} the result is the same, +but there is a clear difference in control points. As a result, combining \type +{..} with \type {--} or \type {---} makes a big difference. Here we get a +non||smooth connection between the curves and the straight line. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2--z3..cycle" ; +\stopuseMPgraphic + +\getbuffer + +As you can see in the next graphic, when we use \type {---}, we get a smooth +connection between the straight line and the rest of the curve. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2---z3..cycle" ; +\stopuseMPgraphic + +\getbuffer + +So far, we have joined the four points as one path. Alternatively, we can +constrict subpaths and connect them using the ampersand symbol, \type {&}. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2 & z2..z3..z0 & cycle" ; +\stopuseMPgraphic + +\getbuffer + +So far we have created a closed path. Closing is done by \type {cycle}. The +following path may look closed but is in fact open. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2..z3..z0" ; +\stopuseMPgraphic + +\getbuffer + +Only a closed path can be filled. The closed alternative looks as follows. We +will see many examples of filled closed paths later on. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2..z3..z0..cycle" ; +\stopuseMPgraphic + +\getbuffer + +Here the final \type {..} will try to make a smooth connection, but because we +already are at the starting point, this is not possible. However, the \type +{cycle} command can automatically connect to the first point. Watch the +difference between the previous and the next path. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2..z3..cycle" ; +\stopuseMPgraphic + +\getbuffer + +It is also possible to combine two paths into one that don't have common head and +tails. First we define an open path: + +\startuseMPgraphic{path} + tmp := "z0..z1..z2" ; +\stopuseMPgraphic + +\getbuffer + +The following path is a closed one, and crosses the previously shown path. + +\startuseMPgraphic{path} + tmp := "z0..z3..z1..cycle" ; +\stopuseMPgraphic + +\getbuffer + +With \type {buildcycle} we can combine two paths into one. + +\startuseMPgraphic{path} + tmp := "buildcycle(z0..z1..z2 , z0..z3..z1..cycle)" ; +\stopuseMPgraphic + +\getbuffer + +We would refer readers to the \METAFONT\ book and the \METAPOST\ manual for an +explanation of the intricacies of the \type {buildcycle} command. It is an +extremely complicated command, and there is just not enough room here to do it +justice. We suffice with saying that the paths should cross at least once before +the \type {buildcycle} command can craft a combined path from two given paths. We +encourage readers to experiment with this command. + +In order to demonstrate another technique of joining paths, we first draw a few +strange paths. The last of these three graphics demonstrates the use of \type +{softjoin}. + +\startuseMPgraphic{path} + tmp := "z0--z1..z2--z3" ; +\stopuseMPgraphic + +\getbuffer + +\startuseMPgraphic{path} + tmp := "z0..z1..z2--z3" ; +\stopuseMPgraphic + +\getbuffer + +Watch how \type {softjoin} removes a point in the process of smoothing a +connection. The smoothness is accomplished by adapting the control points of the +neighbouring points in the appropriate way. + +\startuseMPgraphic{path} + tmp := "z0--z1 softjoin z2--z3" ; +\stopuseMPgraphic + +\getbuffer + +Once a path is known, you can cut off a slice of it. We will demonstrate a few +alternative ways of doing so, but first we show one more time the path that we +take as starting point. + +\startuseMPgraphic{path} + tmp := "z0..z1..z2..z3..cycle" ; +\stopuseMPgraphic + +\getbuffer + +This path is made up out of five points, where the cycle duplicates the first +point and connects the loose ends. The first point has number zero. + +We can use these points in the \type {subpath} command, which takes two +arguments, specifying the range of points to cut of the path specified after the +keyword \type {of}. + +\startuseMPgraphic{path} + tmp := "subpath(2,4) of (z0..z1..z2..z3..cycle)" ; +\stopuseMPgraphic + +\getbuffer + +The new (sub|)|path is a new path with its own points that start numbering at +zero. The next graphic shows both the original and the subpath from point 1 +upto~3. + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3..cycle)" ; + sub := "subpath(1,3)" ; +\stopuseMPgraphic + +\startbuffer[sub] +\startlinecorrection[blank] +\startMPcode + string tmp, sub ; defaultfont := "\truefontname{Mono}" ; + \includeMPgraphic{axis} + \includeMPgraphic{points} + \includeMPgraphic{path} + label.lft(verbatim(tmp),(14.5cm,2.5cm)) ; + label.lft(verbatim(sub),(14.5cm,2.0cm)) ; + sub := sub & " of " & tmp ; + path p ; p := scantokens(tmp) ; + path q ; q := scantokens(sub) ; + drawwholepath p ; swappointlabels := true ; + drawpath q withcolor .625yellow ; + drawpoints q withcolor .625red ; + drawpointlabels q ; +\stopMPcode +\stoplinecorrection +\stopbuffer + +\getbuffer[sub] + +In spite of what you may think, a point is not fixed. This is why in \METAPOST\ a +point along a path is officially called a time. The next example demonstrates +that we can specify any time on the path. + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3..cycle)" ; + sub := "subpath(2.45,3.85)" ; +\stopuseMPgraphic + +\getbuffer[sub] + +Often we want to take a slice starting at a specific point. This is provided by +\type {cutafter} and its companion \type {cutbefore}. Watch out, this time we use +a non||cyclic path. + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3)" ; +\stopuseMPgraphic + +\getbuffer + +When you use \type {cutafter} and \type {cutbefore} it really helps if you know +in what direction the path runs. + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3) cutafter z2" ; +\stopuseMPgraphic + +\getbuffer + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3) cutbefore z1" ; +\stopuseMPgraphic + +\getbuffer + +Here is a somewhat silly way of accomplishing the same thing, but it is a nice +introduction to \METAPOST's \type {point} operation. In order to use this command +effectively, you need to know how many points make up the path. + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3) cutbefore point 2 of (z0..z1..z2..z3)" ; +\stopuseMPgraphic + +\getbuffer + +As with \type {subpath}, you can use fractions to specify the time on the path, +although the resulting point is not necessarily positioned linearly along the +curve. + +\startuseMPgraphic{path} + tmp := "(z0..z1..z2..z3) cutbefore point 2.5 of (z0..z1..z2..z3)" ; +\stopuseMPgraphic + +\getbuffer + +If you really want to know the details of where fraction points are positioned, +you should read the \METAFONT\ book and study the source of \METAFONT\ and +\METAPOST, where you will find the complicated formulas that are used to +calculate smooth curves. + +\startuseMPgraphic{path} + tmp := "z0..z1..cycle" ; +\stopuseMPgraphic + +\getbuffer + +Like any closed path, this path has points where the tangent is horizontal or +vertical. Early in this chapter we mentioned that a pair (or point) can specify a +direction or vector. Although any angle is possible, we often use one of four +predefined directions: + +\starttabulate[|Tl|Tl|] +\HL +\NC right \NC ( 1, 0) \NC \NR +\NC up \NC ( 0, 1) \NC \NR +\NC left \NC (-1, 0) \NC \NR +\NC down \NC ( 0,-1) \NC \NR +\HL +\stoptabulate + +We can use these predefined directions in combination with \type {directionpoint} +and \type {cutafter}. The following command locates the first point on the path +that has a tangent that points vertically upward, and then feeds this point to +the \type {cutafter} command. + +\startuseMPgraphic{path} + tmp := "(z0..z1..cycle) cutafter directionpoint up of (z0..z1..cycle)" ; +\stopuseMPgraphic + +\getbuffer + +You are not limited to predefined direction vectors. You can provide a pair to +indicate a direction. In the next example we use the following cyclic path: + +\startuseMPgraphic{path} + tmp := "z0..z1..cycle" ; +\stopuseMPgraphic + +\getbuffer + +Using \type {( )} is not mandatory but makes the expression look less +complicated. + +\startuseMPgraphic{path} + tmp := "(z0..z1..cycle) cutafter directionpoint (1,1) of (z0..z1..cycle)" ; +\stopuseMPgraphic + +\getbuffer + +We will apply these commands in the next chapters, but first we will finish our +introduction in \METAPOST. We have seen how a path is constructed and what can be +done with it. Now it is time to demonstrate how such a path is turned into a +graphic. + +\stopsection + +\startsection[title={Angles}] + +\index{angles} +\index{rotation} + +You can go from angles to vectors and vice versa using the \type {angle} and +\type {dir} functions. The next example show both in action. + +\startbuffer +pickup pencircle scaled 2mm ; +draw (origin -- dir(45) -- dir(0) -- cycle) + scaled 3cm withcolor .625red ; +draw (origin -- dir(angle(1,1)) -- dir(angle(1,0)) -- cycle) + scaled 3cm shifted (3.5cm,0) withcolor .625yellow ; +draw (origin -- (1,1) -- (1,0) -- cycle) + scaled 3cm shifted (7cm,0) withcolor .625white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The \type {dir} command returns an unit vector, which is why the first two shapes +look different and are smaller than the third one. We can compensate for that by +an additional scaling: + +\startbuffer +pickup pencircle scaled 2mm ; +draw (origin -- dir(45) -- dir(0) -- cycle) + scaled sqrt(2) scaled 3cm withcolor .625red ; +draw (origin -- dir(angle(1,1)) -- dir(angle(1,0)) -- cycle) + scaled sqrt(2) scaled 3cm shifted (4.5cm,0) withcolor .625yellow ; +draw (origin -- (1,1) -- (1,0) -- cycle) + scaled 3cm shifted (9cm,0) withcolor .625white ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Drawing pictures}] + +\index{drawing} + +Once a path is defined, either directly or as a variable, you can turn it into a +picture. You can draw a path, like we did in the previous examples, or you can +fill it, but only if it is closed. + +\startlinecorrection[blank] +\startMPcode +visualizepaths ; +path p ; p := (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..cycle ; +draw p withcolor .625red ; +fill p shifted (7cm,0) withcolor .625white ; +\stopMPcode +\stoplinecorrection + +Drawing is done by applying the \type {draw} command to a path, as in: + +\starttyping +draw (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..cycle ; +\stoptyping + +The rightmost graphic was made with \type {fill}: + +\starttyping +fill (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..cycle ; +\stoptyping + +If you try to duplicate this drawing, you will notice that you will get black +lines instead of red and a black fill instead of a gray one. When drawing or +filling a path, you can give it a color, use all kinds of pens, and achieve +special effects like dashes or arrows. + +\startlinecorrection[blank] +\startMPcode +visualizepaths ; +path p ; p := (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..(2.5cm,1cm)..cycle ; +drawarrow p withcolor .625red ; +draw p shifted (7cm,0) dashed withdots withcolor .625yellow ; +\stopMPcode +\stoplinecorrection + +These two graphics were defined and drawn using the following commands. Later we +will explain how you can set the line width (or penshape in terms of \METAPOST). + +\starttyping +path p ; p := (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..(2.5cm,1cm)..cycle ; +drawarrow p withcolor .625red ; +draw p shifted (7cm,0) dashed withdots withcolor .625yellow ; +\stoptyping + +Once we have drawn one or more paths, we can store them in a picture variable. +The straightforward way to store a picture is to copy it from the current +picture: + +\starttyping +picture pic ; pic := currentpicture ; +\stoptyping + +The following command effectively clears the picture memory and allows us to +start anew. + +\starttyping +currentpicture := nullpicture ; +\stoptyping + +We can shift, rotate and slant the picture stored in \type {pic} as we did with +paths. We can say: + +\starttyping +draw pic rotated 45 withcolor red ; +\stoptyping + +A picture can hold multiple paths. You may compare a picture to grouping as +provided by drawing applications. + +\starttyping +draw (0cm,0cm)--(1cm,1cm) ; draw (1cm,0cm)--(0cm,1cm) ; +picture pic ; pic := currentpicture ; +draw pic shifted (3cm,0cm) ; draw pic shifted (6cm,0cm) ; +pic := currentpicture ; draw pic shifted (0cm,2cm) ; +\stoptyping + +We first draw two paths and store the resulting \quote {cross} in a picture +variable. Then we draw this picture two times, so that we now have three copies +of the cross. We store the accumulated drawing again, so that after duplication, +we finally get six crosses. + +\startlinecorrection[blank] +\startMPcode +path p ; p := (0cm,0cm)--(1cm,1cm) ; +path q ; q := (1cm,0cm)--(0cm,1cm) ; +for i=p,q : + drawpath i ; drawcontrollines i ; drawpoints i ; drawcontrolpoints i ; +endfor ; +picture pic ; pic := currentpicture ; +draw pic shifted (3cm,0cm) ; +draw pic shifted (6cm,0cm) ; +pic := currentpicture ; +draw pic shifted (0cm,2cm) ; +\stopMPcode +\stoplinecorrection + +You can often follow several routes to reach the same solution. Consider for +instance the following graphic. + +\startbuffer[points] +w := 4cm ; h := 2cm ; ww := 1cm ; hh := 1.5cm ; +\stopbuffer + +\startbuffer[common] +drawoptions(withcolor .625white) ; +\stopbuffer + +\startbuffer[background] +fill (unitsquare xscaled w yscaled h) enlarged 2mm withcolor .625yellow ; +\stopbuffer + +\startbuffer[shape] +fill (0,0)--(ww,0)--(ww,hh)--(w,hh)--(w,h)--(0,h)--cycle ; +fill (ww,0)--(w,0)--(w,hh)--cycle ; +\stopbuffer + +\typebuffer[shape] + +\startlinecorrection[blank] +\processMPbuffer[common,points,shape] +\stoplinecorrection + +The points that are used to construct the paths are defined using the constants +\type {w}, \type {h}, \type {ww} and \type {hh}. These are defined as follows: + +\typebuffer[points] + +In this case we draw two shapes that leave part of the rectangle uncovered. If +you have a background, this technique allows the background to \quote {show +through} the graphic. + +\startlinecorrection[blank] +\processMPbuffer[common,points,background,shape] +\stoplinecorrection + +A not uncommon practice when making complicated graphics is to use unfill +operations. Since \METAPOST\ provides one, let us see what happens if we apply +this command. + +\startbuffer[shape] +fill (0,0)--(w,0)--(w,h)--(0,h)--cycle ; +unfill (ww,0)--(w,hh)--(ww,hh)--cycle ; +\stopbuffer + +\typebuffer[shape] + +\startlinecorrection[blank] +\processMPbuffer[common,points,background,shape] +\stoplinecorrection + +This does not always give the desired effect, because \METAPOST's \type {unfill} +is not really an unfill, but a \type {fill} with color \type {background}. Since +this color is white by default, we get what we just showed. So, if we set \type +{background} to \type {black}, using \typ {background := black}, we get: + +\startbuffer[back] +background := black ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[back,common,points,background,shape] +\stoplinecorrection + +Of course, you can set the variable \type {background} to a different color, but +this does not hide the fact that \METAPOST\ lacks a real unfill operation. + +\startbuffer[shape] +fill (0,0)--(0,h)--(w,h)--(w,0)--(ww,0)--(w,hh)--(ww,hh)-- + (ww,0)--cycle ; +\stopbuffer + +\startbuffer[path] +autoarrows := true ; +path p ; p := (0,0)--(0,h)--(w,h)--(w,0)--(ww,0)--(w,hh)--(ww,hh)-- + (ww,0)--cycle ; +draw p withpen pencircle scaled 1mm withcolor .625red; +numeric l ; l := length(p)-1 ; +for i=0 upto l : + drawarrow subpath(i,i+1) of p + withpen pencircle scaled 1mm + withcolor (.5+.5(i/l))*red ; +endfor ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[common,points,background,shape] +\stoplinecorrection + +Since we don't consider this \type {unfill} a suitable operator, you may wonder +how we achieved the above result. + +\typebuffer[shape] + +\startlinecorrection[blank] +\processMPbuffer[common,points,background,shape,path] +\stoplinecorrection + +This feature depends on the \POSTSCRIPT\ way of filling closed paths, which comes +down to filling either the left or the right hand side of a curve. The following +alternative works too. + +\startbuffer[shape] +fill (0,0)--(0,h)--(w,h)--(w,hh)--(ww,hh)--(ww,0)--(w,hh)-- + (w,0)--cycle ; +\stopbuffer + +\typebuffer[shape] + +\startlinecorrection[blank] +\processMPbuffer[common,points,background,shape] +\stoplinecorrection + +The next alternative will fail. This has to do with the change in direction at +point \type {(0,0)} halfway through the path. Sometimes changing direction can +give curious but desirable effects, but here it brings no good. + +\startbuffer[shape] +fill (0,0)--(0,h)--(w,h)--(w,0)--(0,0)--(ww,0)--(ww,hh)-- + (w,hh)--(ww,0)--cycle ; +\stopbuffer + +\typebuffer[shape] + +This path fails because of the way \POSTSCRIPT\ implements its fill operator. +More details on how \POSTSCRIPT\ defines fills can be found in the reference +manuals. + +\startlinecorrection[blank] +\processMPbuffer[common,points,background,shape] +\stoplinecorrection + +Some of the operations we have seen are hard coded into \METAPOST\ and are called +primitives. Others are defined as macros, that is, a sequence of \METAPOST\ +commands. Since they are used often, you may expect \type {draw} and \type {fill} +to be primitives, but they are not. They are macros defined in terms of +primitives. + +Given a path \type {pat}, you can consider a \type {draw} to be defined in terms +of: + +\starttyping +addto currentpicture doublepath pat +\stoptyping + +The \type {fill} command on the other hand is defined as: + +\starttyping +addto currentpicture contour pat +\stoptyping + +Both macros are actually a bit more complicated but this is mainly due to the +fact that they also have to deal with attributes like the pen and color they draw +with. + +You can use \type {doublepath} and \type {contour} directly, but we will use +\type {draw} and \type {fill} whenever possible. + +Given a picture \type {pic}, the following code is valid: + +\starttyping +addto currentpicture also pic +\stoptyping + +You can add pictures to existing picture variables, where \type {currentpicture} +is the picture that is flushed to the output file. Watch the subtle difference +between adding a \type {doublepath}, \type {contour} or \type {picture}. + +\stopsection + +\startsection[title={Variables}] + +\index{variables} + +At this point you may have noted that \METAPOST\ is a programming language. +Contrary to some of today's languages, \METAPOST\ is a simple and clean language. +Actually, it is a macro language. Although \METAPOST\ and \TEX\ are a couple, the +languages differ in many aspects. If you are using both, you will sometimes wish +that features present in one would be available in the other. When using both +languages, in the end you will understand why the conceptual differences make +sense. + +Being written in \PASCAL, it will be no surprise that \METAPOST\ has some +\PASCAL||like features, although some may also recognize features from \ALGOL68\ +in it. + +First there is the concept of variables and assignments. There are several data +types, some of which we already have seen. + +\starttabulate +\HL +\NC numeric \NC real number in the range $-4096 \ldots +4096$ \NC \NR +\NC boolean \NC a variable that takes one of two states: true or false \NC \NR +\NC pair \NC point or vector in 2||dimensional space \NC \NR +\NC path \NC a piecewise collection of curves and line segments \NC \NR +\NC picture \NC collection of stroked or filled paths \NC \NR +\NC string \NC sequence of characters, like \type {"metapost"} \NC \NR +\NC color \NC vector of three (rgb) or four (cmyk) numbers \NC \NR +\HL +\stoptabulate + +There are two additional types, \type {transform} and \type {pen}, but we will +not discuss these in depth. + +\starttabulate +\HL +\NC transform \NC transformation vector with six elements \NC \NR +\NC pen \NC pen specification \NC \NR +\HL +\stoptabulate + +You can achieve interesting effects by using pens with certain shapes. For the +moment you may consider a pen to be a path itself that is applied to the path +that is drawn. + +The \type {numeric} data type is used so often that it is the default type of any +non declared variable. This means that + +\starttyping +n := 10 ; +\stoptyping + +is the same as + +\starttyping +numeric n ; n := 10 ; +\stoptyping + +When writing collections of macros, it makes sense to use the second method, +because you can never be sure if \type {n} isn't already declared as a picture +variable, and assigning a numeric to a picture variable is not permitted. + +Because we often deal with collections of objects, such as a series of points, +all variables can be organized in arrays. For instance: + +\starttyping +numeric n[] ; n[3] := 10 ; n[5] := 13 ; +\stoptyping + +An array is a collection of variables of the same type that are assigned and +accessed by indexing the variable name, as in \type {n[3] := 5}. +Multi||dimensional arrays are also supported. Since you need a bit of imagination +to find an application for 5||dimensional arrays, we restrict ourselves to a +two||dimensional example. + +\starttyping +numeric n[][] ; n[2][3] := 10 ; +\stoptyping + +A nice feature is that the bounds of such an array needs not to be set +beforehand. This also means that each cell that you access is reported as {\em +unknown} unless you have assigned it a value. + +Behind the screens there are not really arrays. It's just a matter of creating +hash entries. It might not be obvious, but the following assignments are all +equivalent: + +\startbuffer +i_111_222 := 1cm ; +i_[111]_[222] := 1cm ; +i_[111][222] := 1cm ; +draw + image ( + draw (0cm,i_111_222) ; + draw (1cm,i_[111]_[222]) ; + draw (2cm,i_[111][222]) ; + ) + withpen pencircle scaled 5mm + withcolor .625 red ; +\stopbuffer + +\typebuffer + +Sometimes \METAPOST\ ways are mysterious: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Conditions}] + +\index{conditions} + +The existence of boolean variables indicates the presence of conditionals. +Indeed, the general form of \METAPOST's conditional follows: + +\starttyping +if n=10 : draw p ; else : draw q ; fi ; +\stoptyping + +Watch the colons after the if and else clause. They may not be omitted. The +semi||colons on the other hand, are optional and depend on the context. You may +say things like: + +\starttyping +draw if n=10 : p ; else : q ; fi ; +\stoptyping + +Here we can omit a few semi||colons: + +\starttyping +draw if n=10 : p else : q fi withcolor red ; +\stoptyping + +Adding semi||colons after \type {p} and \type {q} will definitely result in an +error message, since the semi||colon ends the draw operation and \typ {withcolor +red} becomes an isolated piece of nonsense. + +There is no case statement available, but for most purposes, the following +extension is adequate: + +\starttyping +draw p withcolor if n<10 : red elseif n=10 : green else : blue fi ; +\stoptyping + +There is a wide repertoire of boolean tests available. + +\starttyping +if picture p : +if known n : +if odd i : +if cycle q : +\stoptyping + +Of course, you can use \type {and}, \type {or}, \type {not}, and \type {( )} to +construct very advanced boolean expressions. If you have a bit of programming +experience, you will appreciate the extensive support of conditionals in +\METAPOST. + +\stopsection + +\startsection[title={Loops}] + +\index{loops} + +Yet another programming concept present in \METAPOST\ is the loop statement, the +familiar \quote {for loop} of all programming languages. + +\starttyping +for i=0 step 2 until 20 : + draw (0,i) ; +endfor ; +\stoptyping + +As explained convincingly in Niklaus Wirth's book on algorithms and +datastructures, the for loop is the natural companion to an array. Given an array +of length $n$, you can construct a path out of the points that make up the array. + +\starttyping +draw for i=0 step 1 until n-1 : p[i] .. endfor p[n] ; +\stoptyping + +If the step increment is not explicitly stated, it has an assumed value of 1. We +can shorten the previous loop construct as follows: + +\starttyping +draw for i=0 upto n-1 : p[i] .. endfor p[n] ; +\stoptyping + +After seeing \type {if} in action, the following \type {for} loop will be no +surprise: + +\startbuffer +draw origin for i=0 step 10 until 100 : ..{down}(i,0) endfor ; +\stopbuffer + +\typebuffer + +This gives the zig||zag curve: + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +You can use a loop to iterate over a list of objects. A simple 3||step iteration +is: + +\starttyping +for i=p,q,r : + fill i withcolor .8white ; + draw i withcolor red ; +endfor ; +\stoptyping +Using \type {for} in this manner can sometimes save a bit of typing. The list can +contain any expression, and may be of different types. + +In the previous example the \type {i} is an independent variable, local to the +for loop. If you want to change the loop variable itself, you need to use \type +{forsuffixes}. In the next loop the paths \type {p}, \type {q} and~\type {r} are +all shifted. + +\starttyping +forsuffixes i = p, q, r : + i := i shifted (3cm,2cm) ; +endfor ; +\stoptyping + +Sometimes you may want to loop forever until a specific condition occurs. For +this, \METAPOST\ provides a special looping mechanism: + +\startbuffer[demo] +numeric done[][], i, j, n ; n := 0 ; +forever : + i := round(uniformdeviate(10)) ; j := round(uniformdeviate(2)) ; + if unknown done[i][j] : + drawdot (i*cm,j*cm) ; n := n + 1 ; done[i][j] := n ; + fi ; + exitif n = 10 ; +endfor ; +\stopbuffer + +\typebuffer[demo] + +Here we remain in the loop until we have 10 points placed. We use an array to +keep track of placed points. The \METAPOST\ macro \type {uniformdeviate(n)} +returns a random number between 0 and~n and the \type {round} command is used to +move the result toward the nearest integer. The \type {unknown} primitive allows +us to test if the array element already exists, otherwise we exit the +conditional. This saves a bit of computational time as each point is drawn and +indexed only once. + +\startbuffer[pen] +pickup pencircle scaled 2mm ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[pen,demo] +\stoplinecorrection + +The loop terminator \type {exitif} and its companion \type {exitunless} can be +used in \type {for}, \type {forsuffixes} and \type {forever}. + +\stopsection + +\startsection[title={Macros}] + +\index{macros} +\index{definitions} + +In the previous section we introduced \type {upto}. Actually this is not part of +the built in syntax, but a sort of shortcut, defined by: + +\starttyping +def upto = step 1 until enddef ; +\stoptyping + +You just saw a macro definition where \type {upto} is the name of the macro. The +counterpart of \type {upto} is \type {downto}. Whenever you use \type {upto}, it +is replaced by \typ {step 1 until}. This replacement is called expansion. + +There are several types of macros. A primary macro is used to define your own +operators. For example: + +\starttyping +primarydef p doublescaled s = + p xscaled (s/2) yscaled (s*2) +enddef ; +\stoptyping + +Once defined, the \type {doublescaled} macro is implemented as in the following +example: + +\starttyping +draw somepath doublescaled 2cm withcolor red ; +\stoptyping + +When this command is executed, the macro is expanded. Thus, the actual content of +this command becomes: + +\starttyping +draw somepath xscaled 1cm yscaled 4cm withcolor red ; +\stoptyping + +If in the definition of \type {doublescaled} we had added a semi||colon after +\type {(s*2)}, we could not have set the color, because the semicolon ends the +statement. The \type {draw} expects a path, so the macro can best return one. + +A macro can take one or more arguments, as in: + +\starttyping +def drawrandomscaledpath (expr p, s) = + draw p xscaled (s/2) yscaled (s*2) ; +enddef ; +\stoptyping + +When using this macro, it is expected that you will pass it two parameters, the +first being a path, the second a numeric scale factor. + +\starttyping +drawrandomscaledpath(fullsquare, 3cm) ; +\stoptyping + +Sometimes we want to return a value from a macro. In that case we must make sure +that any calculations don't interfere with the expectations. Consider: + +\starttyping +vardef randomscaledpath(expr p, s) = + numeric r ; r := round(1 + uniformdeviate(4)) ; + p xscaled (s/r) yscaled (s*r) +enddef ; +\stoptyping + +Because we want to use the same value of \type {r} twice, we have to use an +intermediate variable. By using a \type {vardef} we hide everything but the last +statement. It is important to distinguish \type {def} macros from those defined +with \type {vardef}. In the latter case, \type {vardef} macros are not a simple +expansion and replacement. Rather, \type {vardef} macros return the value of +their last statement. In the case of the \type {randomscaledpath} macro, a path +is returned. This macro is used in the following manner: + +\starttyping +path mypath ; mypath := randomscaledpath(unitsquare,4cm) ; +\stoptyping + +Note that we send \type {randomscaledpath} a path (\type {unitsquare}) and a +scaling factor (\type {4cm}). The macro returns a scaled path which is then +stored in the path variable \type {mypath}. + +The following argument types are accepted: + +\starttabulate +\HL +\NC expr \NC something that can be assigned to a variable \NC \NR +\NC text \NC arbitrary \METAPOST\ code ending with a \type {;} \NC \NR +\NC suffix \NC a variable bound to another variable \NC \NR +\HL +\stoptabulate +An expression is passed by value. This means that in the body of the macro, a +copy is used and the original is left untouched. On the other hand, any change to +a variable passed as suffix is also applied to the original. + +Local variables must be handled in a special manner, since they may conflict with +variables used elsewhere. This is because all variables are global by default. +The way out of this problem is using grouping in combination with saving +variables. The use of grouping is not restricted to macros and may be used +anywhere in your code. Variables saved and declared in a group are local to that +group. Once the group is exited the variables cease to exist. + +\starttyping +vardef randomscaledpath(expr p, s) = + begingroup ; save r ; numeric r ; + r := round(1 + uniformdeviate(4)) ; + p xscaled (s/r) yscaled (s*r) + endgroup +enddef ; +\stoptyping + +In this particular case, we could have omitted the grouping, since \type {vardef} +macros are always grouped automatically. Therefore, we could have defined the +macro as: + +\starttyping +vardef randomscaledpath(expr p, s) = + save r ; numeric r ; r := round(1 + uniformdeviate(4)) ; + p xscaled (s/r) yscaled (s*r) +enddef ; +\stoptyping + +The command \type {save r} declares that the variable \type {r} is local to the +macro. Thus, any changes to the (new) numeric variable \type {r} are local and +will not interfere with a variable \type {r} defined outside the macro. This is +important to understand, as variables outside the macro are global and accessible +to the code within the body of the macro. + +Macro definitions may be nested, but since most \METAPOST\ code is relatively +simple, it is seldom needed. Nesting is discouraged as it makes your code less +readable. + +Besides \type {def} and \type {vardef}, \METAPOST\ also provides the classifiers +\type {primarydef}, \type {secondarydef} and \type {tertiarydef}. You can use +these classifiers to define macros like those provided by \METAPOST\ itself: + +\starttyping +primarydef x mod y = ... enddef ; +secondarydef p intersectionpoint q = ... enddef ; +tertiarydef p softjoin q = ... enddef ; +\stoptyping +A primary macro acts like the binary operators \type {*} or \type {scaled} and +\type {shifted}. Secondary macros are like \type {+}, \type {-} and logical \type +{or}, and take less precedence. The tertiary operators like \type {<} or the path +and string concatenation operator \type {&} have tertiary macros as companions. +More details can be found in the \METAFONT\ book. When it comes to taking +precedence, \METAPOST\ tries to be as natural as possible, in the sense that you +need to provide as few \type {( )}'s as possible. When in doubt, or when +surprised by unexpected results, use parentheses. + +\stopsection + +\startsection[title={Arguments}] + +\index{arguments} +\index{macros+arguments} + +The \METAPOST\ macro language is rather flexible in how you feed arguments to +macros. If you have only one argument, the following definitions and calls are +valid. + +\starttyping +def test expr a = enddef ; test (a) ; test a ; +def test (expr a) = enddef ; test (a) ; test a ; +\stoptyping + +A more complex definition is the following. As you can see, you can call the +\type {test} macro in your favorite way. + +\starttyping +def test (expr a,b) (expr c,d) = enddef ; + +test (a) (b) (c) (d) ; +test (a,b) (c,d) ; +test (a,b,c) (d) ; +test (a,b,c,d) ; +\stoptyping + +The type of the arguments is one of \type {expr}, \type {primary} or \type +{suffix}. When fetching arguments, \METAPOST\ uses the type to determine how and +what to grab. A fourth type is \type {text}. When no parenthesis are used, a +\type {text} argument grabs everything upto the next semicolon. + +\starttyping +def test (expr a) text b = enddef ; + +test (a) ; test (a) b ; +\stoptyping + +You can use a \type {text} to grab arguments like \typ {withpen pencircle scaled +10 withcolor red}. Because \type {text} is so hungry, you may occasionally need a +two stage definition: + +\starttyping +def test expr a = dotext(a) enddef ; +def dotest (expr a) text b = ... enddef ; + +test a ; test a b ; +\stoptyping + +This definition permits arguments without parenthesis, which is something you +want with commands like \type {draw}. + +The \type {vardef} alternative behaves in a similar way. It always provides +grouping. You need to generate a return value and as a result may not end with a +semicolon. + +You may consider the whole \type {vardef} to be encapsulated into parenthesis and +thereby to be a (self contained) variable. Adding additional parenthesis often +does more harm than good: + +\starttyping +vardef test (expr a) = + ( do tricky things with a ; manipulated_a ) +enddef ; +\stoptyping + +Here the tricky things become part of the return value, which quite certainly is +something that you don't want. + +The three operator look||alike macro definitions are less flexible and have the +definition scheme: + +\starttyping +primarydef x test y = enddef ; +secondarydef x test y = enddef ; +tertiarydef x test y = enddef ; +\stoptyping + +When defining macros using this threesome you need to be aware of the associated +priorities. When using these definitions, you also have to provide your own +grouping. + +In the plain \METAPOST\ macro collection (\type {plain.mp}) you can find many +examples of clever definitions. The following (simplified) version of \type {min} +demonstrates how we use the argument handler to isolate the first argument from +the provided list, simply by using two arguments. + +\starttyping +vardef min (expr u) (text t) = + save min_u ; min_u := u ; + for uu = t : if uu<u : min_u := uu ; fi endfor + min_u +enddef ; +\stoptyping + +The special sequence \type {@#} is used to pick up a so called delimited argument: + +\starttyping +vardef TryMe@#(expr x) = + % we can now use @#, which is just text +enddef ; +\stoptyping + +This feature is used in the definition of \type {z} as used in \type {z1} or +\type {z234}: + +\starttyping +vardef z@# = (x@#,y@#) enddef ; +\stoptyping + +Other applications can be found in the label drawing macros where the anchor +point is assigned to the obscure variable \type {@#}. + +\stopsection + +\startsection[title={Pens}] + +\index{pens} + +When drawing, three attributes can be applied to it: a dashpattern, a pen +and|/|or a color. You may consider an arrowhead an attribute, but actually it is +just an additional drawing, appended to the path. + +The (predefined) \type {pencircle} attribute looks like: + +\starttyping +withpen pencircle +\stoptyping + +where \type {pencircle} is a special kind of path, stored in a pen variable. Like +any path, you can transform it. You can scale it equally in all directions: + +\starttyping +withpen pencircle scaled 1mm +\stoptyping + +You can also provide unequal scales, creating an elliptically shaped and rotated +pen. + +\starttyping +withpen pencircle xscaled 2mm yscaled 4mm rotated 30 +\stoptyping + +In the following graphic, the circle in the center is drawn without any option, +which means that the default pen is used, being a pencircle with a radius of half +a base point. The other three circles are drawn with different pen +specifications. + +\startlinecorrection[blank] +\startMPcode +path p ; p := fullcircle scaled 1cm ; +drawoptions (withcolor .625yellow) ; +draw p ; +drawoptions (withcolor .625red) ; +draw p scaled 2 withpen pencircle ; +drawoptions (withcolor .625yellow) ; +draw p scaled 3 withpen pencircle scaled 1mm ; +drawoptions (withcolor .625red) ; +draw p scaled 4 withpen pencircle xscaled 2mm yscaled 4mm rotated 30 ; +\stopMPcode +\stoplinecorrection + +If you forget about the colors, the \METAPOST\ code to achieve this is as +follows. + +\starttyping +path p ; p := fullcircle scaled 1cm ; +draw p ; +draw p scaled 2 withpen pencircle ; +draw p scaled 3 withpen pencircle scaled 1mm ; +draw p scaled 4 withpen pencircle xscaled 2mm yscaled 4mm rotated 30 ; +\stoptyping + +If this were the only way of specifying a pen, we would be faced with a +considerable amount of typing, particularly in situations where we use pens +similar to the fourth specification above. For that reason, \METAPOST\ supports +the concept of a current pen. The best way to set this pen is to use the \type +{pickup} macro. + +\starttyping +pickup pencircle xscaled 2mm yscaled 4mm rotated 30 ; +\stoptyping + +This macro also stores some characteristics of the pen in variables, so that they +can be used in (the more complicated) calculations that are involved in +situations like drawing font||like graphics. + +If we substitute \type {pencircle} by \type {pensquare}, we get a different kind +of shapes. In the non rotated pens, the top, bottom, left and right parts of the +curve are thinner. + +\startlinecorrection[blank] +\startMPcode +path p ; p := fullcircle scaled 1cm ; +drawoptions (withcolor .625yellow) ; +draw p ; +drawoptions (withcolor .625red) ; +draw p scaled 2 withpen pensquare ; +drawoptions (withcolor .625yellow) ; +draw p scaled 3 withpen pensquare scaled 1mm ; +drawoptions (withcolor .625red) ; +draw p scaled 4 withpen pensquare xscaled 2mm yscaled 4mm rotated 30 ; +\stopMPcode +\stoplinecorrection + +You should look at pens in the way an artist does. He follows a shape and in +doing so he or she twists the pen (and thereby the nib) and puts more or less +pressure on it. + +The chance that you have an appropriate pen laying at your desk is not so big, +but you can simulate the following \METAPOST's pen by taking two pencils and +holding them together in one hand. If you position them in a 45 degrees angle, +and draw a circle, you will get something like: + +\startlinecorrection[blank] +\startMPcode +path p ; p := fullcircle xscaled 2cm yscaled 3cm ; +drawoptions(withcolor .625red withpen pencircle scaled .5mm); +draw p ; draw p shifted (.3cm,.3cm) ; +\stopMPcode +\stoplinecorrection + +If you take a calligraphic pen with a thin edge of .5cm, you will get: + +\startlinecorrection[blank] +\startMPcode +drawoptions(withcolor .625red); +path p ; p := fullcircle xscaled 2cm yscaled 3cm ; +draw p withpen makepen ((0,0)--(.3cm,.3cm)) withcolor .625white ; +drawoptions(withcolor .625red withpen pencircle scaled .25mm); +draw p ; draw p shifted (.3cm,.3cm) ; +\stopMPcode +\stoplinecorrection + +You can define such a pen yourself: + +\starttyping +path p ; p := fullcircle xscaled 2cm yscaled 3cm ; +pen doublepen ; doublepen := makepen ((0,0)--(.3cm,.3cm)) ; +pickup doublepen ; draw p ; +\stoptyping + +Here we define a new pen using the \type {pen} command. Then we define a path, +and make a pen out of it using the \type {makepen} macro. The path should be a +relatively simple one, otherwise \METAPOST\ will complain. + +You can use \type {makepen} with the previously introduced \type {withpen}: + +\starttyping +draw p withpen makepen ((0,0)--(.3cm,.3cm)) ; +\stoptyping + +and \type {pickup}: + +\starttyping +pickup makepen ((0,0)--(.3cm,.3cm)) ; draw p ; +\stoptyping + +You can use \type {makepen} and \type {makepath} to convert paths into pens and +vice versa. + +Pens are very important when defining fonts, and \METAFONT\ is meant to be a font +creation tool. Since \METAPOST\ has a slightly different audience, it lacks some +features in this area, but offers a few others instead. Nevertheless, one can try +to design a font using \METAPOST. Of course, pens are among the designers best +kept secrets. But even then, not every~O is a nice looking one. + +\startlinecorrection[blank] +\startMPcode +path p ; p := fullcircle xscaled 2cm yscaled 3cm ; +draw p withpen makepen (unitsquare scaled .4cm superellipsed .85) +withcolor .625white ; +\stopMPcode +\stoplinecorrection + +\startbuffer[s00] + path p ; p := (-1,0) {down} .. {up} (1,0) ; + draw pensilled(p, pensquare scaled (1/3)) + scaled 2cm ; + draw boundingbox image(draw p) + scaled 2cm ; +\stopbuffer + +\startbuffer[s30] + path p ; p := (-1,0) {down} .. {up} (1,0) ; + draw pensilled(p, pensquare scaled (1/3) rotated 30) + scaled 2cm ; + draw boundingbox image(draw p) + scaled 2cm ; +\stopbuffer + +\startbuffer[s45] + path p ; p := (-1,0) {down} .. {up} (1,0) ; + draw pensilled(p, pensquare scaled (1/3) rotated 45) + scaled 2cm ; + draw boundingbox image(draw p) + scaled 2cm ; +\stopbuffer + +\startbuffer[c00] + path p ; p := (-1,0) {down} .. {up} (1,0) ; + draw pensilled(p, pencircle scaled (1/3)) + scaled 2cm ; + draw boundingbox image(draw p) + scaled 2cm ; +\stopbuffer + +\startbuffer[c30] + path p ; p := (-1,0) {down} .. {up} (1,0) ; + draw pensilled(p, pencircle scaled (1/3) rotated 30) + scaled 2cm ; + draw boundingbox image(draw p) + scaled 2cm ; +\stopbuffer + +\startbuffer[c45] + path p ; p := (-1,0) {down} .. {up} (1,0) ; + draw pensilled(p, pencircle scaled (1/3) rotated 45) + scaled 2cm ; + draw boundingbox image(draw p) + scaled 2cm ; +\stopbuffer + +\startbuffer[f30] + interim pensilstep := 1/6 ; + draw pensilled(fullcircle, pencircle xscaled (1/10) yscaled (2/10) rotated 30) + scaled 5cm ; + draw boundingbox fullcircle + scaled 5cm ; +\stopbuffer + +The \type {pensilled} macro is a variant on a macro used for testing some border +cases in the engine. It provides a nice way to see what actually happens when a +pen is applied. \in {Figure} [fig:pensilled] demonstrates this macro. The first +row shows a square pen: + +\typebuffer[s30] + +and the second row a circular pen: + +\typebuffer[c30] + +\startplacefigure[title={How pens are applied.},reference=fig:pensilled] + \startcombination[3*2] + {\processMPbuffer[s00]} {\tttf pensquare rotated 0} + {\processMPbuffer[s30]} {\tttf pensquare rotated 30} + {\processMPbuffer[s45]} {\tttf pensquare rotated 45} + {\processMPbuffer[c00]} {\tttf pencircle rotated 0} + {\processMPbuffer[c30]} {\tttf pencircle rotated 30} + {\processMPbuffer[c45]} {\tttf pencircle rotated 45} + \stopcombination +\stopplacefigure + +The effects of rotation and non|-|proportional scaling are demonstrated +in \in {figure} [fig:pensilled:fullcircle]. + +\typebuffer[f30] + +\startplacefigure[title={A proportionally scaled and rotated pen.},reference=fig:pensilled:fullcircle] + \processMPbuffer[f30] +\stopplacefigure + +\stopsection + +\startsection[title={Joining lines}] + +\index{joining} +\index{paths+joining} + +The way lines are joined or end is closely related to the way \POSTSCRIPT\ +handles this. By setting the variables \type {linejoin} and \type {linecap}, you +can influence the drawing process. \in {Figure} [fig:joints] demonstrates the +alternatives. The gray curves are drawn with both variables set to \type +{rounded}. + +\startnotmode[screen] + +\def\showMPline#1#2% + {\startMPcode + path p ; p := ((0,0)--(.5,1)--(1,0)) xscaled 3cm yscaled 1.5cm ; + pickup pencircle scaled 1cm ; + draw p withcolor .625white ; + interim linejoin := #1 ; + interim linecap := #2 ; + draw p withcolor transparent(1,.5,.625yellow) ; + \stopMPcode} + +\stopnotmode + +\startmode[screen] + +\def\showMPline#1#2% + {\startMPcode + path p ; p := ((0,0)--(.5,1)--(1,0)) xscaled 2.5cm yscaled 1.25cm ; + pickup pencircle scaled .75cm ; + draw p withcolor .625white ; + interim linejoin := #1 ; + interim linecap := #2 ; + draw p withcolor transparent(1,.5,.625yellow) ; + \stopMPcode} + +\stopmode + +\def\showMPtext#1#2% + {linejoin=#1\par linecap=#2} + +\startbuffer +\startcombination[3*3] + {\showMPline{mitered}{butt}} {\showMPtext{mitered}{butt}} + {\showMPline{mitered}{rounded}} {\showMPtext{mitered}{rounded}} + {\showMPline{mitered}{squared}} {\showMPtext{mitered}{squared}} + {\showMPline{rounded}{butt}} {\showMPtext{rounded}{butt}} + {\showMPline{rounded}{rounded}} {\showMPtext{rounded}{rounded}} + {\showMPline{rounded}{squared}} {\showMPtext{rounded}{squared}} + {\showMPline{beveled}{butt}} {\showMPtext{beveled}{butt}} + {\showMPline{beveled}{rounded}} {\showMPtext{beveled}{rounded}} + {\showMPline{beveled}{squared}} {\showMPtext{beveled}{squared}} +\stopcombination +\stopbuffer + +\placefigure + [here] [fig:joints] + {The nine ways to end and join lines.} + {\getbuffer} + +By setting the variable \type {miterlimit}, you can influence the mitering of +joints. The next example demonstrates that the value of this variable acts as a +trigger. + +\startbuffer +interim linejoin := mitered ; +for i :=1 step 1 until 5 : + interim miterlimit := i*pt ; + draw ((0,0)--(.5,1)--(1,0)) shifted (1.5i,0) scaled 50pt + withpen pencircle scaled 10pt withcolor .625red ; +endfor ; +\stopbuffer + +\typebuffer + +The variables \type {linejoin}, \type {linecap} and \type {miterlimit} are so +called {\em internal} variables. When we prefix their assignments by \type +{interim}, the setting will be local within groups, like \typ {beginfig ... +endfig}. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Colors}] + +\index{attributes} +\index{color} +So far, we have seen some colors in graphics. It must be said that \METAPOST\ +color model is not that advanced, although playing with colors in the \METAPOST\ +way can be fun. In later chapters we will discuss some extensions that provide +shading. + +Colors are defined as vectors with three components: a red, green and blue one. +Like pens, colors have their \type {with}||command: + +\starttyping +withcolor (.4,.5.,6) +\stoptyping + +You can define color variables, like: + +\starttyping +color darkred ; darkred := (.625,0.0) ; +\stoptyping + +You can now use this color as: + +\starttyping +withcolor darkred +\stoptyping + +Given that \type {red} is already defined, we also could have said: + +\starttyping +withcolor .625red +\stoptyping + +Because for \METAPOST\ colors are just vectors, you can do things similar to +points. A color halfway red and green is therefore accomplished with: + +\starttyping +withcolor .5[red,green] +\stoptyping + +Since only the \RGB\ color space is supported, this is about all we can tell +about colors for this moment. Later we will discuss some nasty details. + +\stopsection + +\startsection[title={Dashes}] + +\index{dashes} + +A dash pattern is a simple picture that is build out of straight lines. Any +slightly more complicated picture will be reduced to straight lines and a real +complicated one is rejected, and in this respect \METAPOST\ considers a circle to +be a complicated path. + +The next example demonstrates how to get a dashed line. First we built picture +\type {p}, that we apply to a path. Here we use a straight path, but dashing can +be applied to any path. + +\startbuffer +picture p ; p := nullpicture ; +addto p doublepath ((0,0)--(3mm,3mm)) shifted (6mm,6mm) ; +draw (0,0)--(10cm,0) dashed p withpen pencircle scaled 1mm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This way of defining a pattern is not that handy, especially if you start +wondering why you need to supply a slanted path. Therefore, \METAPOST\ provides a +more convenient mechanism to define a pattern. + +\startbuffer +picture p ; p := dashpattern(on 3mm off 3mm) ; +draw (0,0)--(10cm,0) dashed p withpen pencircle scaled 1mm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Most dashpatterns can be defined in terms of on and off. This simple on||off +dashpattern is predefined as picture \type {evenly}. Because this is a picture, +you can (and often need to) scale it. + +\startbuffer +draw (0,0)--(10cm,0) dashed (evenly scaled 1mm) + withpen pencircle scaled 1mm ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +Opposite to a defaultpen, there is no default color and default dash pattern set. +The macro \type {drawoptions} provides you a way to set the default attributes. + +\starttyping +drawoptions(dashed evenly withcolor red) ; +\stoptyping + +\stopsection + +\startsection[reference=sec:text,title={Text}] + +\index{text} + +Since \METAFONT\ is meant for designing fonts, the only means for including text +are those that permit you to add labels to positions for the sole purpose of +documentation. + +Because \METAPOST\ is derived from \METAFONT\ it provides labels too, but in +order to let users add more sophisticated text, like a math formula, to a +graphic, it also provides an interface to \TEX. + +Because we will spend a whole chapter on using text in \METAPOST\ we limit the +discussion here to a few fundamentals. + +\startbuffer[font] +defaultfont := "\truefontname{Mono}" ; +defaultscale := .8 ; +\stopbuffer + +\startbuffer[label] +pair a ; a := (3cm,3cm) ; +label.top("top",a) ; label.bot("bot",a) ; +label.lft("lft",a) ; label.rt ("rt" ,a) ; +\stopbuffer + +\typebuffer[label] + +These four labels show up at the position stored in the pair variable \type {a}, +anchored in the way specified after the period. + +\startlinecorrection[blank] +\processMPbuffer[font,label] +\stoplinecorrection + +The command \type {dotlabel} also typesets the point as a rather visible dot. + +\startbuffer[label] +pair a ; a := (3cm,3cm) ; +dotlabel.top("top",a) ; dotlabel.bot("bot",a) ; +dotlabel.lft("lft",a) ; dotlabel.rt ("rt" ,a) ; +\stopbuffer + +\typebuffer[label] + +\startlinecorrection[blank] +\processMPbuffer[font,label] +\stoplinecorrection + +The command \type {thelabel} returns the typeset label as picture that you can +manipulate or draw afterwards. + +\startbuffer[label] +pair a ; a := (3cm,3cm) ; pickup pencircle scaled 1mm ; +drawdot a withcolor .625yellow ; +draw thelabel.rt("the right way",a) withcolor .625red ; +\stopbuffer + +\typebuffer[label] + +You can of course rotate, slant and manipulate such a label picture like any +other picture. + +\startlinecorrection[blank] +\processMPbuffer[font,label] +\stoplinecorrection + +The font can be specified in the string \type {defaultfont} and the scale in +\type {defaultscale}. Labels are defined using the low level operator \type +{infont}. The next statement returns a picture: + +\startbuffer[mp] +draw "this string will become a sequence of glyphs (MP)" + infont defaultfont scaled defaultscale ; +\stopbuffer + +\typebuffer[mp] + +By default the \type {infont} operator is not that clever and does not apply +kerning. Also, typesetting math or accented characters are not supported. The way +out of this problem is using \typ {btex ... etex}. + +\startbuffer[tex] +draw btex this string will become a sequence of glyphs (\TeX) etex ; +\stopbuffer + +\typebuffer[tex] + +The difference between those two methods is shown below. The outcome of \type +{infont} depends on the current setting of the variable \type {defaultfont}. + +\startlinecorrection[blank] +\processMPbuffer[mp] +\processMPbuffer[tex] +\stoplinecorrection + +When you run inside \CONTEXT\ (as we do here) there is no difference between +\type {infont} and the \TEX\ methods. This is because we overload the \type +{infont} operator and also pass its content to \TEX. Both \type {infont} and +\type {btex} use the macro \type {textext} which is intercepted and redirects the +task to \TEX. This happens in the current run so there is no need to pass extra +information about fonts. + +Instead of passing strings to \type {infont}, you can also pass characters, using +\type {char}, for example \type {char(73)}. When you use \type {infont} you +normally expect the font to be \ASCII\ conforming. If this is not the case, you +must make sure that the encoding of the font that you use matches your +expectations. However, as we overload this macro it does not really matter since +the string is passed to \TEX\ anyway. For instance, \UTF\ encoded text should +work fine as \CONTEXT\ itself understands this encoding. + +\stopsection + +\startsection[title={Linear equations}] + +\index{equations} +\index{expressions} + +\startbuffer[a] +\defineMPinstance + [solvers] + [format=metafun, + extensions=yes, + initializations=yes] +\stopbuffer + +\startbuffer[b] +\startMPdefinitions{solvers} +def draw_problem (expr p, q, r, s, show_labels) = + begingroup ; save x, y, a, b, c, d, e, f, g, h ; + + z11 = z42 = p ; z21 = z12 = q ; z31 = z22 = r ; z41 = z32 = s ; + + a = x12 - x11 ; b = y12 - y11 ; c = x22 - x21 ; d = y22 - y21 ; + e = x32 - x31 ; f = y32 - y31 ; g = x42 - x41 ; h = y42 - y41 ; + + z11 = (x11, y11) ; z12 = (x12, y12) ; + z13 = (x12-b, y12+a) ; z14 = (x11-b, y11+a) ; + z21 = (x21, y21) ; z22 = (x22, y22) ; + z23 = (x22-d, y22+c) ; z24 = (x21-d, y21+c) ; + z31 = (x31, y31) ; z32 = (x32, y32) ; + z33 = (x32-f, y32+e) ; z34 = (x31-f, y31+e) ; + z41 = (x41, y41) ; z42 = (x42, y42) ; + z43 = (x42-h, y42+g) ; z44 = (x41-h, y41+g) ; + + pickup pencircle scaled .5pt ; + + draw z11--z12--z13--z14--cycle ; draw z11--z13 ; draw z12--z14 ; + draw z21--z22--z23--z24--cycle ; draw z21--z23 ; draw z22--z24 ; + draw z31--z32--z33--z34--cycle ; draw z31--z33 ; draw z32--z34 ; + draw z41--z42--z43--z44--cycle ; draw z41--z43 ; draw z42--z44 ; + + z1 = 0.5[z11,z13] ; z2 = 0.5[z21,z23] ; + z3 = 0.5[z31,z33] ; z4 = 0.5[z41,z43] ; + + draw z1--z3 dashed evenly ; draw z2--z4 dashed evenly ; + + z0 = whatever[z1,z3] = whatever[z2,z4] ; + mark_rt_angle (z1, z0, z2) ; % z2 is not used at all + + if show_labels > 0 : + draw_problem_labels ; + fi ; + + endgroup ; +enddef ; +\stopMPdefinitions +\stopbuffer + +\startbuffer[c] +\startMPdefinitions{solvers} +angle_radius := 10pt ; + +def mark_rt_angle (expr a, b, c) = + draw ((1,0)--(1,1)--(0,1)) + zscaled (angle_radius*unitvector(a-b)) + shifted b +enddef ; +\stopMPdefinitions +\stopbuffer + +\startbuffer[d] +\startMPdefinitions{solvers} +def draw_problem_labels = + pickup pencircle scaled 5pt ; + + dotlabel.llft("$Z_{11}$", z11) ; dotlabel.ulft("$Z_{12}$", z12) ; + dotlabel.ulft("$Z_{13}$", z13) ; dotlabel.llft("$Z_{14}$", z14) ; + + dotlabel.lrt ("$Z_{21}$", z21) ; dotlabel.llft("$Z_{22}$", z22) ; + dotlabel.urt ("$Z_{23}$", z23) ; dotlabel.ulft("$Z_{24}$", z24) ; + + dotlabel.urt ("$Z_{31}$", z31) ; dotlabel.ulft("$Z_{32}$", z32) ; + dotlabel.urt ("$Z_{33}$", z33) ; dotlabel.urt ("$Z_{34}$", z34) ; + + dotlabel.lrt ("$Z_{41}$", z41) ; dotlabel.urt ("$Z_{42}$", z42) ; + dotlabel.llft("$Z_{43}$", z43) ; dotlabel.lrt ("$Z_{44}$", z44) ; + + dotlabel.urt ("$Z_{0}$", z0) ; + dotlabel.lft ("$Z_{1}$", z1) ; dotlabel.top ("$Z_{2}$", z2) ; + dotlabel.rt ("$Z_{3}$", z3) ; dotlabel.bot ("$Z_{4}$", z4) ; +enddef ; +\stopMPdefinitions +\stopbuffer + +\startbuffer[e] +\startuseMPgraphic{solvers::one}{i,j,s} + draw_problem ( + (400pt,400pt), (300pt,600pt), + \MPvar{i}[(300pt,600pt), (550pt,800pt)], + \MPvar{j}[(400pt,400pt), (550pt,500pt)], + \MPvar{s} + ) ; +\stopuseMPgraphic +\stopbuffer + +\startbuffer[f] +\placefigure + [here][fig:problem] + {The problem.} + {\scale + [width=\textwidth] + {\useMPgraphic{solvers::one}{i=0.6,j=1.0,s=1}}} +\stopbuffer + +In the previous sections, we used the assignment operator \type {:=} to assign a +value to a variable. Although for most of the graphics that we will present in +later chapters, an assignment is appropriate, specifying a graphic in terms of +expressions is not only more flexible, but also more in the spirit of the +designers of \METAFONT\ and \METAPOST. + +The \METAFONT\ book and \METAPOST\ manual provide lots of examples, some of which +involve math that we don't consider to belong to everyones repertoire. But, even +for non mathematicians using expressions can be a rewarding challenge. + +The next introduction to linear equations is based on my first experiences with +\METAPOST\ and involves a mathematical challenge posed by a friend. I quickly +ascertained that a graphical proof was far more easy than some proof with a lot +of $\sin (this)$ and $\cos (that)$ and long forgotten formulas. + +I was expected to prove that the lines connecting the centers of four squares +drawn upon the four sides of a quadrilateral were perpendicular (see \in {figure} +[fig:problem]). + +\getbuffer[a,b,c,d,e] + +\getbuffer[f] + +This graphic was generated with the following command: + +\typebuffer[f] + +We will use this example to introduce a few new concepts, one being instances. In +a large document there can be many \METAPOST\ graphics and they might fall in +different categories. In this manual we have graphics that are generated as part +of the style as wel as examples that show what \METAFUN\ can do. As definitions +and variables in \METAPOST\ are global by default, there is a possibility that we +end up with clashes. This can be avoided by grouping graphics in instances. Here +we create an instance for the example that we're about to show. + +\typebuffer[a] + +We can now limit the scope of definitions to this specific instance. Let's start +with the macro that takes care of drawing the solution to our problem. The macro +accepts four pairs of coordinates that determine the central quadrilateral. All +of them are expressions. + +\typebuffer[b] + +Because we want to call this macro more than once, we first have to save the +locally used values. Instead of declaring local variables, one can hide their use +from the outside world. In most cases variables behave globally. If we don't save +them, subsequent calls will lead to errors due to conflicting equations. We can +omit the grouping commands, because we wrap the graphic in a figure, and figures +are grouped already. + +We will use the predefined \type {z} variable, or actually a macro that returns a +variable. This variable has two components, an \type {x} and \type {y} +coordinate. So, we don't save \type {z}, but the related variables \type {x} and +\type {y}. + +Next we draw four squares and instead of hard coding their corner points, we use +\METAPOST's equation solver. Watch the use of \type {=} which means that we just +state dependencies. In languages like \PERL, the equal sign is used in +assignments, but in \METAPOST\ it is used to express relations. + +In a first version, we will just name a lot of simple relations, as we can read +them from a sketch drawn on paper. So, we end up with quite some \type {z} +related expressions. + +For those interested in the mathematics behind this code, we add a short +explanation. Absolutely key to the construction is the fact that you traverse the +original quadrilateral in a clockwise orientation. What is really going on here +is vector geometry. You calculate the vector from $z_{11}$ to $z_{12}$ (the first +side of the original quadrilateral) with: + +\starttyping +(a,b) = z12 - z11 ; +\stoptyping + +This gives a vector that points from $z_{11}$ to $z_{12}$. Now, how about an +image that shows that the vector $(-b,a)$ is a 90 degree rotation in the +counterclockwise direction. Thus, the points $z_{13}$ and $z_{14}$ are easily +calculated with vector addition. + +\starttyping +z13 = z12 + (-b,a) ; +z14 = z11 + (-b,a) ; +\stoptyping + +This pattern continues as you move around the original quadrilateral in a +clockwise manner. \footnote {Thanks to David Arnold for this bonus explanation.} + +The code that calculates the pairs \type {a} through \type {h}, can be written in +a more compact way. + +\starttyping +(a,b) = z12 - z11 ; (c,d) = z22 - z21 ; +(e,f) = z32 - z31 ; (g,h) = z42 - z41 ; +\stoptyping + +The centers of each square can also be calculated by \METAPOST. The next lines +define that those points are positioned halfway the extremes. + +\starttyping +z1 = 0.5[z11,z13] ; z2 = 0.5[z21,z23] ; +z3 = 0.5[z31,z33] ; z4 = 0.5[z41,z43] ; +\stoptyping + +Once we have defined the relations we can let \METAPOST\ solve the equations. +This is triggered when a variable is needed, for instance when we draw the +squares and their diagonals. We connect the centers of the squares using a dashed +line style. + +Just to be complete, we add a symbol that marks the right angle. First we +determine the common point of the two lines, that lays at {\em whatever} point +\METAPOST\ finds suitable. + +The definition of \type {mark_rt_angle} is copied from the \METAPOST\ manual and +shows how compact a definition can be (see \at {page} [zscaled] for an +introduction to \type {zscaled}). + +\typebuffer[c] + +So far, most equations are rather simple, and in order to solve them, \METAPOST\ +did not have to work real hard. The only boundary condition is that in order to +find a solution, \METAPOST\ must be able to solve all dependencies. + +The actual value of the \type {whatever} variable is that it saves us from +introducing a slew of variables that will never be used again. We could write: + +\starttyping +z0 = A[z1,z3] = B[z2,z4] ; +\stoptyping + +and get the same result, but the \type {whatever} variable saves us the trouble +of introducing intermediate variables for which we have no use once the +calculation is finished. + +The macro \type{mark_rt_angle} draws the angle symbol and later we will see how +it is defined. First we draw the labels. Unfortunately we cannot package \typ +{btex ... etex} into a macro, because it is processed in a rather special way. +Each \typ {btex ... etex} occurance is filtered from the source and converted +into a snippet of \TEX\ code. When passed through \TEX, each snippet becomes a +page, and an auxiliary program converts each page into a \METAPOST\ picture +definition, which is loaded by \METAPOST. The limitation lays in the fact that +the filtering is done independent from the \METAPOST\ run, which means that loops +(and other code) are not seen at all. Later we will introduce the \METAFUN\ way +around this. + +In order to get all the labels typeset, we have to put a lot of code here. The +macro \type {dotlabel} draws a dot and places the typeset label. + +\typebuffer[d] + +Watch out: as we are in \CONTEXT, we can pass regular \TEX\ code to the label +macro. In a standalone \METAPOST\ run you'd have to use the \type {btex} variant. + +We are going to draw a lot of pictures, so we define an extra macro. This time we +hard||code some values. The fractions \type {i} and \type {j} are responsible for +the visual iteration process, while \type {s} determines the labels. We pass +these variables to the graphic using an extra argument. When you define the +(useable) graphic you need to tell what variables it can expect. + +\typebuffer[e] + +Of course we could have used a loop construct here, but defining auxiliary macros +probably takes more time than simply calling the drawing macro directly. The +results are shown on a separate page (\in{figure}[fig:solution]). + +\startbuffer[x] +\def\MyTest#1#2% + {\scale + [width=.25\textwidth] + {\useMPgraphic{solvers::one}{i=#1,j=#2,s=0}}} +\stopbuffer + +\startbuffer[y] + \startcombination[3*4] + {\MyTest{1.0}{1.0}} {1.0 / 1.0} {\MyTest{0.8}{1.0}} {0.8 / 1.0} + {\MyTest{0.6}{1.0}} {0.6 / 1.0} {\MyTest{0.4}{1.0}} {0.4 / 1.0} + {\MyTest{0.2}{1.0}} {0.2 / 1.0} {\MyTest{0.0}{1.0}} {0.0 / 1.0} + {\MyTest{0.0}{1.0}} {0.0 / 1.0} {\MyTest{0.0}{0.8}} {0.0 / 0.8} + {\MyTest{0.0}{0.6}} {0.0 / 0.6} {\MyTest{0.0}{0.4}} {0.0 / 0.4} + {\MyTest{0.0}{0.2}} {0.0 / 0.2} {\MyTest{0.0}{0.0}} {0.0 / 0.0} + \stopcombination +\stopbuffer + +We will use a helper macro (that saves us typing): + +\typebuffer[x] + +We now can say: + +\typebuffer[y] + +Watch how we pass the settings to the graphic definition using an extra argument. +We force using the \type {solvers} instance by prefixing the name. + +\startpostponing + + \startnotmode[screen] + \placefigure + [here][fig:solution] + {The solution.} + {\getbuffer[x,y]} + \stopnotmode + + \startmode[screen] + \placefigure + [here][fig:solution] + {The solution.} + {\getbuffer[x,y]} + \stopmode + + \page + +\stoppostponing + +It does not need that much imagination to see the four sided problem converge to +a three sided one, which itself converges to a two sided one. In the two sided +alternative it's not that hard to prove that the angle is indeed 90 degrees. + +As soon as you can see a clear pattern in some code, it's time to consider using +loops. In the previous code, we used semi indexes, like \type {12} in \type +{z12}. In this case \type{12} does reflect something related to square~1 and~2, +but in reality the 12 is just twelve. This does not harm our expressions. + +A different approach is to use a two dimensional array. In doing so, we can +access the variables more easily using loops. If we omit the labels, and angle +macro, the previously defined macro can be reduced considerably. + +\starttyping +def draw_problem (expr n, p, q, r, s) = % number and 4 positions + begingroup ; save x, y ; + + z[1][1] = p ; z[2][1] = q ; z[3][1] = r ; z[4][1] = s ; + + for i=1 upto 4 : + z[i][1] = (x[i][1],y[i][1]) = z[if i=1: 4 else: i-1 fi][2] ; + z[i][2] = (x[i][2],y[i][2]) ; + z[i][3] = (x[i][2]-y[i][2]+y[i][1], y[i][2]+x[i][2]-x[i][1]) ; + z[i][4] = (x[i][1]-y[i][2]+y[i][1], y[i][1]+x[i][2]-x[i][1]) ; + z[i] = 0.5[z[i][1],z[i][3]] ; + endfor ; + + z[0] = whatever[z[1],z[3]] = whatever[z[2],z[4]] ; + + pickup pencircle scaled .5pt ; + + for i=1 upto 4 : + draw z[i][1]--z[i][2]--z[i][3]--z[i][4]--cycle ; + draw z[i][1]--z[i][3] ; draw z[i][2]--z[i][4] ; + if i<3 : draw z[i]--z[i+2] dashed evenly fi ; + endfor ; + + draw ((1,0)--(1,1)--(0,1)) + zscaled (unitvector(z[1]-z[0])*10pt) + shifted z[0] ; + + endgroup ; +enddef ; +\stoptyping + +I think that we could argue quite some time about the readability of this code. +If you start from a sketch, and the series of equations does a good job, there is +hardly any need for such improvements to the code. On the other hand, there are +situations where the simplified (reduced) case can be extended more easily, for +instance to handle 10 points instead of~4. It all depends on how you want to +spend your free hours. + +\stopsection + +\startsection[title={Clipping}] + +\index{clipping} + +For applications that do something with a drawing, for instance \TEX\ embedding a +graphic in a text flow, it is important to know the dimensions of the graphic. +The maximum dimensions of a graphic are specified by its bounding box. + +\startlinecorrection[blank] +\startMPcode +path p ; p := fullcircle scaled 3cm ; +draw p withpen pencircle scaled 1mm withcolor .625red ; +draw boundingbox p withpen pencircle scaled .1mm ; +draw llcorner boundingbox p withpen pencircle scaled 2mm withcolor .625yellow ; +draw urcorner boundingbox p withpen pencircle scaled 2mm withcolor .625yellow ; +\stopMPcode +\stoplinecorrection + +A bounding box is defined by its lower left and upper right corners. If you open +the \POSTSCRIPT\ file produced by \METAPOST, you may find lines like: + +\starttyping +%%BoundingBox: -46 -46 46 46 +\stoptyping + +or, when supported, + +\starttyping +%%HiResBoundingBox: -45.35432 -45.35432 45.35432 45.35432 +\stoptyping + +The first two numbers define the lower left corner and the last two numbers the +upper right corner. From these values, you can calculate the width and height of +the graphic. + +A graphic may extend beyond its bounding box. It depends on the application that +uses the graphic whether that part of the graphic is shown. + +In \METAPOST\ you can ask for all four points of the bounding box of a path or +picture as well as the center. + +\starttabulate[|lT|l|] +\HL +\NC llcorner p \NC lower left corner \NC \NR +\NC lrcorner p \NC lower right corner \NC \NR +\NC urcorner p \NC upper right corner \NC \NR +\NC ulcorner p \NC upper left corner \NC \NR +\NC center p \NC the center point \NC \NR +\HL +\stoptabulate + +You can construct the bounding box of path~\type {p} out of the four points +mentioned: + +\starttyping +llcorner p -- lrcorner p -- urcorner p -- ulcorner p -- cycle +\stoptyping + +You can set the bounding box of a picture, which can be handy if you want to +build a picture in steps and show the intermediate results using the same +dimensions as the final picture, or when you want to show only a small piece. + +\startbuffer +fill fullcircle scaled 2cm withcolor .625yellow ; +setbounds currentpicture to unitsquare scaled 1cm ; +draw unitsquare scaled 1cm withcolor .625red ; +\stopbuffer + +\typebuffer + +Here, we set the bounding box with the command \type {setbounds}, which takes a +path. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The graphic extends beyond the bounding box, but the bounding box determines the +placement and therefore the spacing around the graphic. We can get rid of the +artwork outside the bounding box by clipping it. + +\startbuffer +fill fullcircle scaled 2cm withcolor .625yellow ; +clip currentpicture to unitsquare scaled 1cm ; +\stopbuffer + +\typebuffer + +The resulting picture is just as large but shows less of the picture. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Some extensions}] + +We will now encounter a couple of transformations that can make your life easy +when you use \METAPOST\ for making graphics like the ones demonstrated in this +document. These transformations are not part of standard \METAPOST, but come with +\METAFUN. + +A very handy extension is \type {enlarged}. Although you can feed it with any +path, it will return a rectangle larger or smaller than the boundingbox of that +path. You can specify a pair or a numeric. + +\startbuffer +path p ; p := fullsquare scaled 2cm ; +drawpath p ; drawpoints p ; +p := (p shifted (3cm,0)) enlarged (.5cm,.25cm) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +There are a few more alternatives, like \type {bottomenlarged}, \type +{rightenlarged}, \type {topenlarged} and \type {leftenlarged}. + +The \type {cornered} operator will replace sharp corners by rounded ones (we +could not use \type {rounded} because this is already in use). + +\startbuffer +path p ; p := ((1,0)--(2,0)--(2,2)--(1,2)--(0,1)--cycle) + xysized (4cm,2cm) ; +drawpath p ; drawpoints p ; +p := (p shifted (5cm,0)) cornered .5cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +The \type {smoothed} operation is a less subtle one, since it operates on the +bounding box and thereby can result in a different shape. + +\startbuffer +path p ; p := ((1,0)--(2,0)--(2,2)--cycle) xysized (4cm,2cm) ; +drawpath p ; drawpoints p ; +p := (p shifted (5cm,0)) smoothed .5cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +The next one, \type {simplified}, can be applied to paths that are constructed +automatically. Instead of testing for duplicate points during construction, you +can clean up the path afterwards. + +\startbuffer +path p ; p := + ((0,0)--(1,0)--(2,0)--(2,1)--(2,2)--(1,2)--(0,2)--(0,1)--cycle) + xysized (4cm,2cm) ; +drawpath p ; drawpoints p ; +p := simplified (p shifted (5cm,0)) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +A cousin of the previous operation is \type {unspiked}. This one removes ugly +left|-|overs. It works well for the average case. + +\startbuffer +path p ; p := + ((0,0)--(2,0)--(3,1)--(2,0)--(2,2)--(1,2)--(1,3)--(1,2)--(0,1)--cycle) + xysized (4cm,2cm) ; +drawpath p ; drawpoints p ; +p := unspiked (p shifted (5cm,0)) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +There are a couple of operations that manipulate the path in more drastic ways. +Take \type {randomized}. + +\startbuffer +path p ; p := fullsquare scaled 2cm ; +drawpath p ; drawpoints p ; +p := (p shifted (5cm,0)) randomized .5cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Or how about \type {squeezed}: + +\startbuffer +path p ; p := fullsquare scaled 2cm randomized .5cm ; +drawpath p ; drawpoints p ; +p := (p shifted (5cm,0)) squeezed .5cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +A \type {punked} path is, like a punked font, a font with less smooth curves (in +our case, only straight lines). + +\startbuffer +path p ; p := fullcircle scaled 2cm randomized .5cm ; +drawpath p ; drawpoints p ; +p := punked (p shifted (5cm,0)) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +A \type {curved} path on the other hand has smooth connections. Where in many +cases a punked path becomes smaller, a curved path will be larger. + +\startbuffer +path p ; p := fullsquare scaled 2cm randomized .5cm ; +drawpath p ; drawpoints p ; +p := curved (p shifted (5cm,0)) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Probably less usefull (although we use it in one of the \OPENTYPE\ visualizers) +is \type {laddered}: + +\startbuffer +path p ; p := fullcircle scaled 3cm ; +drawpath p ; drawpoints p ; +p := laddered (p shifted (5cm,0)) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +When writing \PPCHTEX\ (that can be used to draw chemical structure formulas) I +needed a parallelizing macro, so here it is: + +\startbuffer +path p ; p := fullcircle scaled 3cm ; +drawpath p ; drawpoints p ; +p := p paralleled 1cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +If you use a negative argument (like \type {-1cm}) the parallel line will be +drawn at the other side. + +The \type {blownup} operation scales the path but keeps the center in the same +place. + +\startbuffer +path p ; p := fullsquare xyscaled (4cm,1cm) randomized .5cm ; +drawpath p ; drawpoints p ; +p := p blownup .5cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +The \type {shortened} operation also scales the path but only makes it longer or +shorter. This macro only works on straight paths. + +\startbuffer +path p ; p := (0,0) -- (2cm,3cm) ; +drawpath p ; drawpoints p ; +p := p shortened 1cm ; +drawpath p ; drawpoints p ; +p := p shortened -1cm ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Here are a few more drawing helpers. Even if you don't need them you might at +some point take a look at their definitions to see what happens there. First we +give a square round corners with \type {roundedsquare}: + +\startbuffer +path p ; p := roundedsquare(2cm,4cm,.25cm) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Next we draw a square|-|like circle (or circle|-|like square) using \type +{tensecircle}: + +\startbuffer +path p ; p := tensecircle(2cm,4cm,.25cm) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Often I make such helpers in the process of writing larger drawing systems. Take +\type {crossed}: + +\startbuffer +path p ; p := origin crossed 1cm ; +drawpath p ; drawpoints p ; +p := (origin crossed fullcircle scaled 2cm crossed .5cm) shifted (3cm,0) ; +drawpath p ; drawpoints p ; +\stopbuffer + +\typebuffer + +These examples demonstrate that a path is made up out of points (something that +you probably already knew by now). The \METAPOST\ operator \type {of} can be used +to \quote {access} a certain point at a curve. + +\startbuffer +path p ; p := fullsquare xyscaled (3cm,2cm) randomized .5cm ; +drawpath p ; drawpoints p ; drawpointlabels p ; +draw point 2.25 of p withpen pencircle scaled 5mm withcolor .625red ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +To this we add two more operators: \type {on} and \type {along}. With \type {on} +you get the point at the supplied distance from point~0; with \type {along} you +get the point at the fraction of the length of the path. + +\startbuffer +path p, q, r ; +p := fullsquare xyscaled (2cm,2cm) randomized .5cm ; +q := p shifted (3cm,0) ; r := q shifted (3cm,0) ; +drawpath p ; drawpoints p ; drawpointlabels p ; +drawpath q ; drawpoints q ; drawpointlabels q ; +drawpath r ; drawpoints r ; drawpointlabels r ; +pickup pencircle scaled 5mm ; +draw point 2.25 of p withcolor .625red ; +draw point 2.50cm on q withcolor .625yellow ; +draw point .45 along r withcolor .625white ; +\stopbuffer + +\typebuffer + +Beware: the \type {length} of a path is the number of points minus one. The +shapes below are constructed from 5~points and a length of~4. If you want the +length as dimension, you should use \type {arclength}. + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +We will now play a bit with simple lines. With \type {cutends}, you can (indeed) +cut off the ends of a curve. The specification is a dimension. + +\startbuffer +path p ; p := (0cm,0cm) -- (4cm,1cm) ; +path q ; q := (5cm,0cm){right} .. (9cm,1cm) ; +drawpath p ; drawpoints p ; drawpath q ; drawpoints q ; +p := p cutends .5cm ; q := q cutends .5cm ; +drawpathoptions (withpen pencircle scaled 5pt withcolor .625yellow) ; +drawpointoptions(withpen pencircle scaled 4pt withcolor .625red) ; +drawpath p ; drawpoints p ; drawpath q ; drawpoints q ; +resetdrawoptions ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +As with more operators, \type {cutends} accepts a numeric or a pair. Watch the +subtle difference between the next and the previous use of \type {cutends}. + +\startbuffer +path p ; p := (0cm,0) .. (4cm,0) .. (8cm,0) .. (4cm,0) .. cycle ; +drawpath p ; drawpoints p ; p := p cutends (2cm,1cm) ; +drawpathoptions (withpen pencircle scaled 5pt withcolor .625yellow) ; +drawpointoptions(withpen pencircle scaled 4pt withcolor .625red) ; +drawpath p ; drawpoints p ; +resetdrawoptions ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +When \type {stretched} is applied to a path, it is scaled but the starting point +(point~0) keeps its location. The specification is a scale. + +\startbuffer +path p ; p := (0cm,0) .. (3cm,1cm) .. (4cm,0) .. (5cm,1cm) ; +drawpath p ; drawpoints p ; p := p stretched 1.1 ; +drawpathoptions (withpen pencircle scaled 2.5pt withcolor .625yellow) ; +drawpointoptions(withpen pencircle scaled 4.0pt withcolor .625red) ; +drawpath p ; drawpoints p ; resetdrawoptions ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +We can scale in two directions independently or even in one direction by +providing a zero value. In the next example we apply the stretch two times. + +\startbuffer +path p ; p := (0cm,0) .. (3cm,1cm) .. (4cm,0) .. (5cm,1cm) ; +drawpath p ; drawpoints p ; p := p stretched (.75,1.25) ; +drawpathoptions (withpen pencircle scaled 2.5pt withcolor .625yellow) ; +drawpointoptions(withpen pencircle scaled 4.0pt withcolor .625red) ; +drawpath p ; drawpoints p ; p := p stretched (0,1.5) ; +drawpathoptions (withpen pencircle scaled 4.0pt withcolor .625red) ; +drawpointoptions(withpen pencircle scaled 2.5pt withcolor .625yellow) ; +drawpath p ; drawpoints p ; resetdrawoptions ; +\stopbuffer + +\typebuffer + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +We already met the \type {randomize} operator. This one is the chameleon under +the operators. + +\startbuffer +draw fullsquare xyscaled (4cm,2cm) + randomized .25cm + shifted origin randomized (1cm, 2cm) + withcolor red randomized (.625, .850) + withpen pencircle scaled (5pt randomized 1pt) ; +\stopbuffer + +\typebuffer + +So, \type {randomized} can handle a numeric, pair, path and color, and its +specification can be a numeric, pair or color, depending on what we're dealing +with. + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +In the previous example we also see \type {xyscaled} in action. Opposite to \type +{scaled}, \type {xscaled} and \type {yscaled}, this is not one of \METAPOST\ +build in features. The same is true for the \type {.sized} operators. + +\startbuffer[a] +picture p ; p := image + ( draw fullsquare + xyscaled (300,800) + withpen pencircle scaled 50 + withcolor .625 yellow ; ) ; +draw p xysized (3cm,2cm) shifted (bbwidth(currentpicture)+.5cm,0) ; +draw p xysized 2cm shifted (bbwidth(currentpicture)+.5cm,0) ; +draw p xsized 1cm shifted (bbwidth(currentpicture)+.5cm,0) ; +draw p ysized 2cm shifted (bbwidth(currentpicture)+.5cm,0) ; +\stopbuffer + +\typebuffer[a] + +\startlinecorrection[blank] \processMPbuffer[a] \stoplinecorrection + +Here, the \type {image} macro creates an (actually rather large) picture. The +last four lines actually draw this picture, but at the given dimensions. Watch +how the line width scales accordingly. If you don't want this, you can add the +following line: + +\startbuffer[b] +redraw currentpicture withpen pencircle scaled 2pt ; +draw boundingbox currenpicture withpen pencircle scaled .5mm ; +\stopbuffer + +\typebuffer[b] + +Watch how the boundingbox is not affected: + +\startlinecorrection[blank] \processMPbuffer[a,b] \stoplinecorrection + +In this example we also used \type {bbwidth} (which has a companion macro \type +{bbheight}). You can apply this macro to a path or a picture. + +In fact you don't always need to follow this complex route if you want to simply +redraw a path with another pen or color. + +\startbuffer +draw fullcircle scaled 1cm + withcolor .625red withpen pencircle scaled 1mm ; +draw currentpicture + withcolor .625yellow withpen pencircle scaled 3mm ; +draw boundingbox currentpicture + withpen pencircle scaled .5mm ; +\stopbuffer + +\typebuffer + +This is what you will get from this: + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +If you want to add a background color to a picture you can do that afterwards. +This can be handy when you don't know in advance what size the picture will have. + +\startbuffer +fill fullcircle scaled 1cm withcolor .625red ; +addbackground withcolor .625 yellow ; +\stopbuffer + +\typebuffer + +The background is just a filled rectangle that gets the same size as the current +picture, that is put on top of it. + +\startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +\stopsection + +\startsection[title={Cutting and pasting}] + +\index{paths+cutting} +\index{cutting} + +When enhancing or building a graphic, often parts of already constructed paths +are needed. The \type {subpath}, \type {cutbefore} and \type {cutafter} operators +can be used to split paths in smaller pieces. In order to do so, we must know +where we are on the path that is involved. For this we use points on the path. +Unfortunately we can only use these points when we know where they are located. +In this section we will combine some techniques discussed in previous sections. +We will define a few macros, manipulate some paths and draw curves and points. + +\startbuffer +path p ; p := fullcircle yscaled 3cm xscaled .9TextWidth ; +drawpath p ; drawpoints p withcolor .625red ; drawpointlabels p ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +This circle is drawn by scaling the predefined path \type {fullcircle}. This path +is constructed using 8~points. As you can see, these points are not distributed +equally along the path. In the following graphic, the second and third point of +the curve are colored red, and point 2.5 is colored yellow. Point~0 is marked in +black. This point is positioned halfway between point~2 and~3. + +\startbuffer +path p ; p := fullcircle scaled 3cm xscaled 2 ; +pickup pencircle scaled 5mm ; autoarrows := true ; +drawarrow p withcolor .625white ; +draw point 0.0 of p ; +draw point 2.0 of p withcolor .625red ; +draw point 2.5 of p withcolor .625yellow ; +draw point 3.0 of p withcolor .625red ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +It is clear that, unless you know exactly how the path is constructed, other +methods should be available. A specific point on a path is accessed by \typ +{point ... of}, but the next example demonstrates two more alternatives. + +\startbuffer +path p ; p := fullcircle scaled 3cm xscaled 2 ; +pickup pencircle scaled 5mm ; +draw p withcolor .625white ; +draw point 3 of p withcolor .625red ; +draw point .6 along p withcolor .625yellow ; +draw point 3cm on p ; +\stopbuffer + +\typebuffer + +So, in addition to \type {on} to specify a point by number (in \METAPOST\ +terminology called time), we have \type {along} to specify a point as fraction of +the path, and \type {on} to specify the position in a dimension. + +\startlinecorrection[blank] +\processMPbuffer +\stoplinecorrection + +The \type {on} and \type {along} operators are macros and can be defined as: + +\starttyping +primarydef len on pat = + (arctime len of pat) of pat +enddef ; + +primarydef pct along pat = + (arctime (pct * (arclength pat)) of pat) of pat +enddef ; +\stoptyping + +These macros introduce two new primitives, \type {arctime} and \type {arclength}. +While \type {arctime} returns a number denoting the time of the point on the +path, \type {arclength} returns a dimension. + +\quotation {When mathematicians draw parametric curves, they frequently need to +indicate the direction of motion. I often have need of a little macro that will +put an arrow of requested length, anchored at a point on the curve, and bending +with the curve in the direction of motion.} + +When David Arnold asked me how this could be achieved, the fact that a length was +requested meant that the solution should be sought in using the primitives and +macros we introduced a few paragraphs before. Say that we want to call for such +an arrow as follows. + +\startbuffer[a] +path p ; p := fullcircle scaled 3cm ; +pair q ; q := point .4 along p ; +pickup pencircle scaled 2mm ; +draw p withcolor .625white ; +drawarrow somearrow(p,q,2cm) withcolor .625red ; +draw q withcolor .625yellow ; +\stopbuffer + +\typebuffer[a] + +Because we want to follow the path, we need to construct the arrow from this +path. Therefore, we first reduce the path by cutting off the part before the +given point. Next we cut off the end of the resulting path so that we keep a +slice that has the length that was asked for. Since we can only cut at points, we +determine this point using the \type {arctime} primitive. + +\startbuffer[b] +vardef somearrow (expr pat, loc, len) = + save p ; path p ; p := pat cutbefore loc ; + (p cutafter point (arctime len of p) of p) +enddef ; +\stopbuffer + +\typebuffer[b] + +By using a \type {vardef} we hide the intermediate assignments. Such \type +{vardef} is automatically surrounded by \type {begingroup} and \type {endgroup}, +so the \type {save} is local to this macro. When processed, this code produces +the following graphic: + +\startbuffer[c] +autoarrows := true ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[c,b,a] +\stoplinecorrection + +This graphic shows that we need a bit more control over the exact position of the +arrow. It would be nice if we could start the arrow at the point, or end there, +or center the arrow around the point. Therefore, the real implementation is a bit +more advanced. + +\startbuffer +vardef pointarrow (expr pat, loc, len, off) = + save l, r, s, t ; path l, r ; numeric s ; pair t ; + t := if pair loc : loc else : point loc along pat fi ; + s := len/2 - off ; if s<=0 : s := 0 elseif s>len : s := len fi ; + r := pat cutbefore t ; + r := (r cutafter point (arctime s of r) of r) ; + s := len/2 + off ; if s<=0 : s := 0 elseif s>len : s := len fi ; + l := reverse (pat cutafter t) ; + l := (reverse (l cutafter point (arctime s of l) of l)) ; + (l..r) +enddef ; +\stopbuffer + +\typebuffer + +This code fragment also demonstrates how we can treat the \type {loc} argument as +pair (coordinates) or fraction of the path. We calculate the piece of path before +and after the given point separately and paste them afterwards as \type {(l..r)}. +By adding braces we can manipulate the path in expressions without the danger of +handling \type {r} alone. + +We can now implement left, center and right arrows by providing this macro the +right parameters. The offset (the fourth parameter), is responsible for a +backward displacement. This may seem strange, but negative values would be even +more confusing. + +\startbuffer +def rightarrow (expr p,t,l) = pointarrow(p,t,l,-l) enddef ; +def leftarrow (expr p,t,l) = pointarrow(p,t,l,+l) enddef ; +def centerarrow(expr p,t,l) = pointarrow(p,t,l, 0) enddef ; +\stopbuffer + +\typebuffer + +We can now apply this macro as follows: + +\startbuffer[a] +path p ; p := fullcircle scaled 3cm ; +pickup pencircle scaled 2mm ; +draw p withcolor .625white ; +drawarrow leftarrow (p, .4 ,2cm) withcolor .625red ; +drawarrow centerarrow(p,point 5 of p,2cm) withcolor .625yellow ; +draw point .4 along p withcolor .625yellow ; +draw point 5 of p withcolor .625red ; +\stopbuffer + +\typebuffer[a] + +\startlinecorrection[blank] +\processMPbuffer[a] +\stoplinecorrection + +Watch how we can pass a point (\typ {point 5 of p}) as well as a fraction (\type +{.4}). The following graphic demonstrates a few more alternatives. + +\startbuffer[a] +pickup pencircle scaled 2mm; autoarrows := true ; + +path p ; p := fullcircle yscaled 3cm xscaled .9TextWidth ; + +draw p withcolor .5white; + +for i=1, 2, 3 : + drawdot point i of p withpen pencircle scaled 5mm withcolor .625white ; +endfor ; +for i=.60, .75, .90 : + drawdot point i along p withpen pencircle scaled 5mm withcolor .625white ; +endfor ; +\stopbuffer + +\startbuffer[b] +drawarrow leftarrow (p,point 1 of p,2cm) withcolor red ; +drawarrow centerarrow (p,point 2 of p,2cm) withcolor blue ; +drawarrow rightarrow (p,point 3 of p,2cm) withcolor green ; +drawarrow pointarrow (p,.60,4cm,+.5cm) withcolor yellow ; +drawarrow pointarrow (p,.75,3cm,-.5cm) withcolor cyan ; +drawarrow centerarrow (p,.90,3cm) withcolor magenta ; +\stopbuffer + +\startlinecorrection[blank] +\processMPbuffer[a,b] +\stoplinecorrection + +The arrows are drawn using the previously defined macros. Watch the positive and +negative offsets in call to \type {pointarrow}. + +\typebuffer[b] + +\stopsection + +\startsection[title={Current picture}] + +\index {pictures} + +When you draw paths, texts and|/|or pictures they are added to the so called +current picture. You can manipulate this current picture as is demonstrated in +this manual. Let's show a few current picture related tricks. + +\startbuffer + draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ; +\stopbuffer + +\typebuffer \startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +We can manipulate the picture as a whole: + +\startbuffer + draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ; + currentpicture := currentpicture slanted .5 ; +\stopbuffer + +\typebuffer \startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Sometimes it's handy to temporarily set aside the current picture. + +\startbuffer + draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ; + currentpicture := currentpicture slanted .5 ; + pushcurrentpicture ; + draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625yellow ; + currentpicture := currentpicture slanted -.5 ; + popcurrentpicture ; +\stopbuffer + +\typebuffer \startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +These are \METAFUN\ commands but \METAPOST\ itself comes with a variant, \type +{image}, and you explicitly have to draw this picture (or otherwise add it to the +currentpicture). + +\startbuffer + draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ; + currentpicture := currentpicture slanted .5 ; + draw image ( + draw fullcircle scaled 1cm + withpen pencircle scaled 1mm withcolor .625yellow ; + currentpicture := currentpicture slanted -.5 ; + ) ; +\stopbuffer + +\typebuffer \startlinecorrection[blank] \processMPbuffer \stoplinecorrection + +Each graphic starts fresh with an empty current picture. In \METAFUN\ we make +sure that we also reset some otherwise global variables, like color, pen and some +line properties. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/metafun.tex b/doc/context/sources/general/manuals/metafun/metafun.tex new file mode 100644 index 000000000..dc90bb611 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/metafun.tex @@ -0,0 +1,108 @@ +% language=uk macros=mkvi + +% author : Hans Hagen +% copyright : PRAGMA ADE & ConTeXt Development Team +% license : Creative Commons Attribution ShareAlike 4.0 International +% reference : pragma-ade.nl | contextgarden.net | texlive (related) distributions +% origin : the ConTeXt distribution +% +% comment : Because this manual is distributed with TeX distributions it comes with a rather +% liberal license. We try to adapt these documents to upgrades in the (sub)systems +% that they describe. Using parts of the content otherwise can therefore conflict +% with existing functionality and we cannot be held responsible for that. Many of +% the manuals contain characteristic graphics and personal notes or examples that +% make no sense when used out-of-context. +% +% comment : Some chapters might have been published in TugBoat, the NTG Maps, the ConTeXt +% Group journal or otherwise. Thanks to the editors for corrections. Also thanks +% to users for testing, feedback and corrections. +% +% comment : This manual was originally written for MkII and as a consequence many examples +% are coded in a bit different way than we would nowadays do in MkIV. But, as we +% try to be downward compatible, it doesn't hurt. +% +% comment : I also use this manual for benchmarking ConTeXt MkIV. On my current machine (a +% 2013 dell i7 laptop) one run takes some 18.1 seconds for LuaTeX and around 14.2 +% seconds for LuajitTeX which is quite okay given the amount of graphics (428 +% pages). +% +% comment : This is one of the manuals that can be ordered at http://www.h2o-books.com and +% it's actually meant to be read on paper. + +\enabledirectives[hyphenator.optimize] +\enabledirectives[hyphenator.flatten] +% \setuphyphenation[method=traditional] + +% \enabletrackers[*defin*] + +% \enablemode[screen] +\enablemode[print] +% \enablemode[book] + +% \usemodule[luacalls] + +% todo: check startintro .. stopintro each chapter + +% \showframe + +\startproduct metafun + +\environment metafun-environment + +\startnotmode[screen] + \component metafun-titlepage-paper + \component metafun-colofon-paper +\stopnotmode + +\startmode[screen] + \environment metafun-environment-screen + \component metafun-titlepage-screen +\stopmode + +\startfrontmatter + \component metafun-introduction + \component metafun-contents + \component metafun-conventions +\stopfrontmatter + +\startbodymatter + \component metafun-welcome + \component metafun-basics + \component metafun-embedding + \component metafun-layout + \component metafun-positioning + \component metafun-backgrounds + \component metafun-gadgets + \component metafun-effects + \component metafun-functions + \component metafun-text + \component metafun-debugging + \component metafun-styles + \component metafun-examples + \component metafun-macros + \component metafun-lua + %component metafun-graphics + \component metafun-sneaky +\stopbodymatter + +\startappendices + % \component metafun-programs + \component metafun-syntax + \component metafun-document + \component metafun-reference + % \component metafun-literature +\stopappendices + +\startbackmatter + \component metafun-index +\stopbackmatter + +\startmode[screen] + \component metafun-colofon-screen +\stopmode + +\startnotmode[screen] + \component metafun-backpage +\stopnotmode + +\stopproduct diff --git a/doc/context/sources/general/manuals/metafun/mfun-700.tex b/doc/context/sources/general/manuals/metafun/mfun-700.tex new file mode 100644 index 000000000..e393a34f3 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-700.tex @@ -0,0 +1,17 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\starttext + +\TitlePage + {A Few Nice Quotes\\ + A Simple Style Demo\\ + Hans Hagen, August 2000} + +\Topic {Douglas R. Hofstadter} \input douglas \page +\Topic {Donald E. Knuth} \input knuth \page +\Topic {Edward R. Tufte} \input tufte \page +\Topic {Hermann Zapf} \input zapf \page + +\stoptext diff --git a/doc/context/sources/general/manuals/metafun/mfun-771.tex b/doc/context/sources/general/manuals/metafun/mfun-771.tex new file mode 100644 index 000000000..460c16f2a --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-771.tex @@ -0,0 +1,9 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\usemodule[present-organic] + +\setupMPvariables[page][alternative=1] + +\input mfun-700 diff --git a/doc/context/sources/general/manuals/metafun/mfun-772.tex b/doc/context/sources/general/manuals/metafun/mfun-772.tex new file mode 100644 index 000000000..99dec1551 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-772.tex @@ -0,0 +1,9 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\usemodule[present-organic] + +\setupMPvariables[page][alternative=2] + +\input mfun-700 diff --git a/doc/context/sources/general/manuals/metafun/mfun-773.tex b/doc/context/sources/general/manuals/metafun/mfun-773.tex new file mode 100644 index 000000000..daefcfe66 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-773.tex @@ -0,0 +1,9 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\usemodule[present-organic] + +\setupMPvariables[page][alternative=3] + +\input mfun-700 diff --git a/doc/context/sources/general/manuals/metafun/mfun-774.tex b/doc/context/sources/general/manuals/metafun/mfun-774.tex new file mode 100644 index 000000000..725d1199b --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-774.tex @@ -0,0 +1,103 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\usemodule[present-organic] + +\setupMPvariables[page][alternative=1] + +\startuseMPgraphic{page} + + \includeMPgraphic{rightsuperbutton} + + StartPage ; + + path p, q ; + + p := Field[Text][Text] enlarged 36pt superellipsed .90 ; + + fill Page + withcolor \MPcolor{yellow} ; + fill p + withcolor \MPcolor{white} ; + draw p + dashed dashpattern (on 9pt off 9pt) + withpen pencircle scaled 3pt + withcolor \MPcolor{red} ; + + p := Field[Text][Text] enlarged 48pt superellipsed .90 ; + + draw p + dashed dashpattern (on 9pt off 9pt) + withpen pencircle scaled 1.5pt ; + + def right_menu_button (expr nn, rr, pp, xx, yy, ww, hh, dd) = + if (pp>0) and (rr>0) : + q := rightsuperbutton(p,xx,yy,RightEdgeWidth,hh) ; + fill q + withcolor \MPcolor{white} ; + draw ptop + withpen pencircle scaled 1.5pt ; + draw pbot + withpen pencircle scaled 1.5pt ; + draw q + dashed dashpattern (on 9pt off 9pt) + withpen pencircle scaled 3pt + withcolor if rr=2 : \MPcolor{gray} else : \MPcolor{red} fi ; + fi ; + enddef ; + + \MPmenubuttons{right} + + StopPage ; +\stopuseMPgraphic + +\startuseMPgraphic{rightsuperbutton} + +vardef rightsuperbutton (expr pat, xpos, ypos, wid, hei) = + + save p, t, b, edge, shift, width, height ; + path p, ptop, pbot ; pair t, b ; numeric edge, shift, width, height ; + + edge := xpos + wid ; shift := ypos + hei ; + + p := rightpath pat ; + +draw p withpen pencircle scaled 1.5pt ; + + ptop := ((-infinity,shift)--(edge,shift)) ; + pbot := ((-infinity,shift-hei)--(edge,shift-hei)) ; + + t := p intersectionpoint ptop ; + b := p intersectionpoint pbot ; + + label.llft("t",t) ; + label.ulft("b",b) ; + + p := subpath(0,xpart (p intersectiontimes ptop)) of p ; + p := subpath(xpart (p intersectiontimes pbot),length(p)) of p ; + + (p -- t -- point 1 of ptop & + point 1 of ptop -- point 1 of pbot & + point 1 of pbot -- b + -- cycle) + +enddef ; + +\stopuseMPgraphic + + + +\starttext + +\TitlePage + {A Few Nice Quotes\\ + A Simple Style Demo\\ + Hans Hagen, August 2000} + +\Topic {Douglas R. Hofstadter} \input douglas \page +\Topic {Donald E. Knuth} \input knuth \page +\Topic {Edward R. Tufte} \input tufte \page +\Topic {Hermann Zapf} \input zapf \page + +\stoptext diff --git a/doc/context/sources/general/manuals/metafun/mfun-775.tex b/doc/context/sources/general/manuals/metafun/mfun-775.tex new file mode 100644 index 000000000..e9d2b85a7 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-775.tex @@ -0,0 +1,9 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\usemodule[present-organic] + +\setupMPvariables[page][alternative=11] + +\input mfun-700 diff --git a/doc/context/sources/general/manuals/metafun/mfun-776.tex b/doc/context/sources/general/manuals/metafun/mfun-776.tex new file mode 100644 index 000000000..82b5c18dd --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-776.tex @@ -0,0 +1,9 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\usemodule[present-organic] + +\setupMPvariables[page][alternative=12] + +\input mfun-700 diff --git a/doc/context/sources/general/manuals/metafun/mfun-800.tex b/doc/context/sources/general/manuals/metafun/mfun-800.tex new file mode 100644 index 000000000..aa0c1260f --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-800.tex @@ -0,0 +1,27 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\setupMPpage + [offset=1pt, + background=color, + backgroundcolor=gray] + +\definecolor [gray] [s=.625] +\definecolor [red] [r=.625] +\definecolor [yellow] [r=.625,g=.625] + +\startuseMPgraphic{test} + fill fullsquare rotated 45 scaled 4cm + withcolor \MPcolor{yellow} ; +\stopuseMPgraphic + +\starttext + +\startMPpage + \includeMPgraphic{test} + fill fullcircle scaled 3cm + withcolor \MPcolor{red} ; +\stopMPpage + +\stoptext diff --git a/doc/context/sources/general/manuals/metafun/mfun-900.tex b/doc/context/sources/general/manuals/metafun/mfun-900.tex new file mode 100644 index 000000000..c295ec908 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-900.tex @@ -0,0 +1,48 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent mfun-900 + +\environment metafun-environment + +% Page 1 + +\getbuffer[pagetext] + +% Page 2/3 + +\getbuffer[back-0,back-1,pagetext] +\getbuffer[back-0,back-1,pagetext] + +\setupbackgrounds[page][background=] + +% Page 4/5 + +\getbuffer[back-0,back-2,pagetext] +\getbuffer[back-0,back-2,pagetext] + +\setupbackgrounds[page][background=] + +% Page 6/7 + +\getbuffer[back-0,back-3,pagetext] +\getbuffer[back-0,back-3,pagetext] + +\setupbackgrounds[page][background=] + +% Page 8/9 + +\getbuffer[back-0,back-4,pagetext] +\getbuffer[back-0,back-4,pagetext] + +\setupbackgrounds[page][background=] + +% Page 10/11 + +\getbuffer[back-0,back-5,pagetext] +\getbuffer[back-0,back-5,pagetext] + +\setupbackgrounds[page][background=] + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/mfun-901.tex b/doc/context/sources/general/manuals/metafun/mfun-901.tex new file mode 100644 index 000000000..23adf77b4 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-901.tex @@ -0,0 +1,11 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent mfun-901 + +\environment metafun-environment + +\getbuffer[gridpage] + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/mfun-902.tex b/doc/context/sources/general/manuals/metafun/mfun-902.tex new file mode 100644 index 000000000..7c4fed73e --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-902.tex @@ -0,0 +1,11 @@ +% language=uk +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startcomponent mfun-902 + +\environment metafun-environment + +\getbuffer[handwrit] + +\stopcomponent diff --git a/doc/context/sources/general/manuals/metafun/mfun-mrun-demo.mp b/doc/context/sources/general/manuals/metafun/mfun-mrun-demo.mp new file mode 100644 index 000000000..c6589beb5 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mfun-mrun-demo.mp @@ -0,0 +1,212 @@ +%D Downloading + +beginfig (1) ; + + path p, q ; + + p := (0,110)..(50,110) shifted (0,-15)..(100,110)-- + (50,50) shifted (10,0) ..(50,50) shifted (0,2.5).. + (50,50) shifted(-10,0)--cycle ; + q := (5,0)--(95,0)--(95,30)..(50,0) shifted (0,10)..(5,30)--cycle ; + + pickup pencircle scaled 15 ; + drawdot (80,100) withcolor .6red ; + drawdot (65,95) withcolor .6red ; + drawdot (50,95) withcolor .6red ; + drawdot (35,95) withcolor .6red ; + + drawdot (50,60) withcolor .6red ; + drawdot (50,35) withcolor .6red ; + drawdot (50,10) withcolor .6red ; + drawdot (70,10) withcolor .6red ; + drawdot (32.5,10) withcolor .6red ; + + pickup pencircle scaled 5 ; + fill p withcolor .6green ; draw p withcolor .4green ; + fill q withcolor .6green ; draw q withcolor .4green ; + + bboxmargin := 2.5 ; p := bbox currentpicture ; + picture s ; s := currentpicture ; currentpicture := nullpicture ; + + pickup pencircle scaled 2.5 ; + fill p withcolor .4blue ; + addto currentpicture also s ; + +endfig ; + +%D WWW Links + +beginfig (2) ; + + boolean angles [], lengths[], colors [][][] ; + numeric a, l, r, g, b, n ; + path p ; + color c ; + + draw fullsquare scaled 150 withpen pencircle scaled 1 withcolor .5white ; + + n := 0 ; + forever : + a := 6 * round(uniformdeviate 60) ; + l := 40 + round(uniformdeviate 60) ; + r := 2 + round(uniformdeviate 6) ; + g := 2 + round(uniformdeviate 6) ; + b := 2 + round(uniformdeviate 6) ; + if (a>0) and not known angles [a] and not known lengths[l] and not known colors [r][g][b] : + n := n + 1 ; + angles [a] := true ; + lengths[l] := true ; + colors [r][g][b] := true ; + p := (origin--origin shifted (0,.5l)) rotatedaround(origin,a) ; + draw p withpen pencircle scaled 2 withcolor (r/10,g/10,b/10) ; + drawdot point 1 of p withpen pencircle scaled 4 withcolor (r/10,g/10,b/10) ; + p := (origin shifted (0,.5l+8)--origin shifted(0,100)) rotatedaround(origin,a) ; + draw p withpen pencircle scaled 2 withcolor (r/10,g/10,b/10) ; + drawdot point 0 of p withpen pencircle scaled 4 withcolor (r/10,g/10,b/10) ; + fi ; + exitif n >= 60 ; + endfor ; + + drawdot + origin + withpen pencircle scaled 10 + withcolor white ; + + fill + ((fullcircle scaled 130) peepholed (fullsquare scaled 150)) + withcolor (1,1,1)-(1,.62,.06); + + clip currentpicture to fullsquare scaled 130 ; + +endfig ; + +%D Mirrors + +beginfig(3) + + path a, b, p, q ; + pair s, t, u, v ; + color c ; + numeric h, w, r ; + + pickup pencircle scaled 10 ; + + h := 120 ; + w := 80 ; + r := 30 ; + + a := (0,0)..(0,.5h) shifted (-r,0)..(0,h) ; + b := (w,0)..(w,.5h) shifted ( r,0)..(w,h) ; + + draw a withcolor .4white; + draw b withcolor .4white; + + def moved (expr i) = + ((i) - 10 + uniformdeviate 20) + enddef ; + + for i=5 step 10 until h-5 : + s := (point (length(a)*(i/h)) of a) ; + t := (point (length(b)*(1-i/h)) of b) ; + u := (s--t) intersectionpoint ((.25w,0)--(.25w,h)) ; + v := (s--t) intersectionpoint ((.75w,0)--(.75w,h)) ; + p := s..(xpart u,moved(ypart u))..(xpart v,moved(ypart v))..t ; + c := (0,.4+uniformdeviate.55,0) ; + l := length(p) ; + l := .25l+uniformdeviate.5l ; + q := p cutafter point l of p ; + pickup pencircle scaled 2.5 ; + draw p withcolor c ; + pickup pencircle scaled 5 ; + drawdot point 0 of p withcolor c ; + drawdot point infinity of p withcolor c ; + endfor ; + + picture s ; s := currentpicture ; currentpicture := nullpicture ; + + bboxmargin := 2.5 ; fill bbox s withcolor .85white ; + + addto currentpicture also s ; + +endfig; + +%D Team + +def dpuppet (expr v, w) = + v - .5w + uniformdeviate w +enddef ; + +def somepuppet (expr s, r) = + picture p ; p := currentpicture ; currentpicture := nullpicture ; + draw ((-10,0)--(10,0)) ; + for i:=-10 step 5 until 10 : + draw ((i,0)--(dpuppet(i,2),-10)) ; + endfor ; + currentpicture := currentpicture rotated r shifted s ; + addto currentpicture also p ; +enddef ; + +def puppet (expr loc, sca, col) = + picture s ; s := currentpicture ; currentpicture := nullpicture ; + + pair a ; a := (dpuppet( 20,5),dpuppet( 0, 5)) ; + pair b ; b := (dpuppet(-20,5),dpuppet( 0, 5)) ; + pair c ; c := (dpuppet( 30,5),dpuppet(60,10)) ; + pair d ; d := (dpuppet(-30,5),dpuppet(60,10)) ; + pair e ; e := (dpuppet( 0,5),dpuppet(30,10)) ; + pair f ; f := (dpuppet( 0,5),dpuppet(50,10)) ; + pair g ; g := (dpuppet( 0,5),dpuppet(65,10)) ; + + pair f ; f := (.6+uniformdeviate.1)[e,g] ; + + drawoptions (withcolor col) ; + + somepuppet(a,dpuppet( 20,5)) ; + somepuppet(b,dpuppet( -20,5)) ; + somepuppet(c,dpuppet( 120,5)) ; + somepuppet(d,dpuppet(-120,5)) ; + + draw a -- e ; + draw b -- e ; + draw c -- f ; + draw d -- f ; + draw e -- g ; + draw fullcircle scaled 25 shifted (g shifted (0,12.5)); + + drawoptions () ; + + currentpicture := currentpicture scaled sca shifted loc ; + addto currentpicture also s ; +enddef ; + +beginfig (4) ; + + pickup pencircle scaled 0 ; + + color col ; col := (.4,.8,.6) ; + + puppet((-20, 0) ,.20, 0.700col) ; + puppet(( 10,10) ,.30, 0.750col) ; + puppet(( 30,20) ,.40, 0.800col) ; + puppet((-20,30) ,.35, 0.850col) ; + puppet(( 20,60) ,.20, 0.900col) ; + puppet(( -5,65) ,.25, 0.950col) ; + + picture s ; s := currentpicture ; currentpicture := nullpicture ; + + bboxmargin := 15 ; fill bbox s withcolor .8(1,1,0) ; + + addto currentpicture also s withpen pencircle scaled .8 ; + + path b ; bboxmargin := -10 ; b := bbox currentpicture ; + numeric len ; len := length(b) ; + numeric stp ; stp := 20 ; + drawoptions(withpen pencircle scaled .8 withcolor .7red) ; + for i=len/8stp step len/4stp until len+len/8stp : + pair ii ; ii := point (dpuppet(i,len/20stp)) of b ; + pair dd ; dd := (direction i of b) rotated (dpuppet(-90,10)) ; + draw ii shifted -.1dd withpen pencircle scaled 1.2 ; + draw ii--(ii shifted .25dd) ; + endfor ; + +endfig ; diff --git a/doc/context/sources/general/manuals/metafun/mycow.mp b/doc/context/sources/general/manuals/metafun/mycow.mp new file mode 100644 index 000000000..24c3e0f7d --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mycow.mp @@ -0,0 +1,299 @@ +% Converted from PostScript(TM) to MetaPost by pstoedit +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +% MetaPost backend contributed by Scott Pakin <pakin@uiuc.edu> +% pstoedit is Copyright (C) 1993 - 1999 Wolfgang Glunz <wglunz@geocities.com> + +% Generate structured PostScript +prologues := 1; + +% Display a given string with its *baseline* at a given location +% and with a given rotation angle +vardef showtext(expr origin)(expr angle)(expr string) = + draw string infont defaultfont scaled defaultscale + rotated angle shifted origin; +enddef; + +beginfig(1); +drawoptions (withcolor (1,1,1)); +fill (84.3799,618.55)..controls (88.3398,624.38) and (92.5898,622.94)..(96.3398,615.67) + ..controls (101.23,615.6) and (102.46,612.43)..(104.98,610.78) + ..controls (122.62,598.39) and (147.46,607.18)..(167.9,601.92) + ..controls (180.94,598.54) and (190.87,599.76)..(200.09,602.06) + ..controls (220.32,607.25) and (246.1,596.16)..(263.74,603.86) + ..controls (274.75,608.62) and (284.76,605.66)..(292.97,600.91) + ..controls (297.58,597.96) and (299.59,596.09)..(300.96,591.26) + ..controls (306.29,572.54) and (306.29,551.02)..(309.53,530.57) + ..controls (309.53,528.84) and (312.19,526.1)..(312.48,522.07) + ..controls (315.79,511.34) and (316.08,510.12)..(317.16,502.2) + ..controls (317.16,501.34) and (326.52,488.45)..(325.01,479.02) + ..controls (323.93,481.25) and (323.86,482.83)..(321.62,481.68) + ..controls (320.33,479.3) and (320.9,473.9)..(322.56,471.74) + ..controls (320.83,470.81) and (318.46,473.47)..(317.52,475.2) + ..controls (318.17,473.04) and (317.81,470.81)..(316.73,469.3) + ..controls (315.86,472.25) and (316.58,473.18)..(315.36,473.9) + ..controls (313.99,472.9) and (314.21,469.3)..(314.28,466.2) + ..controls (313.49,468.07) and (311.47,472.46)..(312.55,476.42) + ..controls (312.48,484.2) and (308.81,489.1)..(310.32,499.1) + ..controls (310.1,504.43) and (307.3,521.06)..(304.56,524.3) + ..controls (303.12,526.25) and (306.36,510.77)..(306.36,506.16) + ..controls (306.65,500.9) and (307.08,468.72)..(306.43,463.1) + ..controls (306.43,459.22) and (306.22,453.96)..(307.08,452.16) + ..controls (308.74,450.79) and (309.38,450.5)..(309.6,447.98) + ..controls (309.24,446.62) and (308.74,446.04)..(307.73,445.54) + ..controls (306.07,444.6) and (307.37,441.79)..(306.07,439.85) + ..controls (304.49,438.77) and (304.13,441.86)..(303.34,441.86) + ..controls (302.69,441) and (303.05,437.98)..(302.47,436.18) + ..controls (299.66,433.8) and (292.18,432.5)..(289.15,434.66) + ..controls (289.73,440.64) and (291.74,441.58)..(295.63,446.62) + ..controls (298.66,452.59) and (297,460.94)..(296.93,468.14) + ..controls (295.49,480.38) and (289.22,487.3)..(289.44,496.44) + ..controls (287.86,495.72) and (286.42,494.57)..(284.26,494.86) + ..controls (283.39,489.46) and (286.42,484.56)..(284.83,480.82) + ..controls (281.95,471.96) and (277.06,446.62)..(279,437.76) + ..controls (280.01,434.74) and (278.21,433.15)..(277.06,433.94) + ..controls (276.77,433.94) and (276.55,433.94)..(276.41,433.94) + ..controls (276.41,433.94) and (276.55,431.42)..(275.69,430.92) + ..controls (274.1,430.34) and (273.67,431.71)..(272.66,432.14) + ..controls (271.22,430.85) and (272.52,429.48)..(271.15,428.04) + ..controls (267.19,428.04) and (261.36,425.38)..(257.98,428.26) + ..controls (257.33,434.16) and (263.3,436.68)..(266.47,440.71) + ..controls (268.63,446.62) and (271.08,462.89)..(267.77,474.62) + ..controls (267.77,475.56) and (264.38,485.28)..(261.43,488.66) + ..controls (258.7,487.66) and (257.33,485.5)..(253.22,486.29) + ..controls (252.58,484.34) and (253.3,482.33)..(252.22,480.1) + ..controls (251.86,479.52) and (249.34,478.58)..(249.19,481.39) + ..controls (248.98,483.05) and (248.9,486.36)..(248.26,486.72) + ..controls (243.65,486.72) and (233.71,487.08)..(231.77,493.92) + ..controls (219.89,492.34) and (215.93,491.26)..(206.57,493.42) + ..controls (196.63,489.67) and (183.24,506.16)..(174.53,502.2) + ..controls (172.51,496.15) and (173.09,485.64)..(171.65,481.39) + ..controls (169.34,474.77) and (171.14,467.14)..(171.14,456.41) + ..controls (170.57,455.4) and (169.85,454.46)..(168.48,454.46) + ..controls (168.48,453.1) and (169.34,450.86)..(168.62,449.42) + ..controls (167.18,447.62) and (165.89,451.8)..(165.02,444.6) + ..controls (163.15,443.74) and (157.75,442.22)..(155.59,445.18) + ..controls (155.88,448.99) and (158.33,451.3)..(160.13,453.38) + ..controls (161.42,456.91) and (160.99,458.28)..(160.7,461.81) + ..controls (160.99,464.98) and (161.71,468.58)..(161.86,470.09) + ..controls (161.86,473.04) and (162.5,479.3)..(161.14,481.18) + --(159.41,482.69)..controls (157.18,487.22) and (158.33,494.64)..(157.61,500.26) + ..controls (155.81,500.69) and (155.81,500.98)..(154.01,498.31) + ..controls (154.01,494.42) and (153.5,486.36)..(152.35,483.84) + ..controls (149.69,479.81) and (150.84,459.65)..(151.42,448.56) + ..controls (151.78,446.47) and (149.69,447.7)..(149.76,444.74) + ..controls (150.05,442.8) and (147.89,443.59)..(146.09,444.6) + ..controls (145.15,445.18) and (146.59,439.78)..(145.37,439.56) + ..controls (142.34,438.84) and (136.87,438.19)..(135.22,440.71) + ..controls (134.57,444.6) and (137.88,448.06)..(140.62,451.01) + ..controls (143.14,455.83) and (140.9,465.7)..(140.47,476.28) + --(138.89,478.22)..controls (134.86,483.19) and (139.61,496.94)..(136.51,506.23) + ..controls (120.02,514.87) and (122.11,519.19)..(118.73,537.62) + ..controls (115.13,557.64) and (93.3799,567.65)..(79.0598,567.65) + ..controls (73.4399,563.04) and (66.24,563.62)..(58.5398,567.65) + ..controls (55.6599,569.23) and (54.4299,573.19)..(54.5,576.5) + ..controls (52.6299,580.75) and (55.22,582.19)..(59.6199,583.49) + ..controls (62.71,587.81) and (68.6199,594.65)..(69.1899,597.74) + ..controls (70.3398,601.92) and (75.5298,608.11)..(77.7598,609.77) + ..controls (75.8198,613.01) and (74.8098,615.17)..(77.1099,618.55) + ..controls (79.5598,620.14) and (81.7898,616.61)..(84.3799,618.55) + --cycle; +drawoptions (withcolor (0,0,0)); +pickup pencircle scaled 0.636492bp; +draw (84.3799,618.55)..controls (88.3398,624.38) and (92.5898,622.94)..(96.3398,615.67) + ..controls (101.23,615.6) and (102.46,612.43)..(104.98,610.78) + ..controls (122.62,598.39) and (147.46,607.18)..(167.9,601.92) + ..controls (180.94,598.54) and (190.87,599.76)..(200.09,602.06) + ..controls (220.32,607.25) and (246.1,596.16)..(263.74,603.86) + ..controls (274.75,608.62) and (284.76,605.66)..(292.97,600.91) + ..controls (297.58,597.96) and (299.59,596.09)..(300.96,591.26) + ..controls (306.29,572.54) and (306.29,551.02)..(309.53,530.57) + ..controls (309.53,528.84) and (312.19,526.1)..(312.48,522.07) + ..controls (315.79,511.34) and (316.08,510.12)..(317.16,502.2) + ..controls (317.16,501.34) and (326.52,488.45)..(325.01,479.02) + ..controls (323.93,481.25) and (323.86,482.83)..(321.62,481.68) + ..controls (320.33,479.3) and (320.9,473.9)..(322.56,471.74) + ..controls (320.83,470.81) and (318.46,473.47)..(317.52,475.2) + ..controls (318.17,473.04) and (317.81,470.81)..(316.73,469.3) + ..controls (315.86,472.25) and (316.58,473.18)..(315.36,473.9) + ..controls (313.99,472.9) and (314.21,469.3)..(314.28,466.2) + ..controls (313.49,468.07) and (311.47,472.46)..(312.55,476.42) + ..controls (312.48,484.2) and (308.81,489.1)..(310.32,499.1) + ..controls (310.1,504.43) and (307.3,521.06)..(304.56,524.3) + ..controls (303.12,526.25) and (306.36,510.77)..(306.36,506.16) + ..controls (306.65,500.9) and (307.08,468.72)..(306.43,463.1) + ..controls (306.43,459.22) and (306.22,453.96)..(307.08,452.16) + ..controls (308.74,450.79) and (309.38,450.5)..(309.6,447.98) + ..controls (309.24,446.62) and (308.74,446.04)..(307.73,445.54) + ..controls (306.07,444.6) and (307.37,441.79)..(306.07,439.85) + ..controls (304.49,438.77) and (304.13,441.86)..(303.34,441.86) + ..controls (302.69,441) and (303.05,437.98)..(302.47,436.18) + ..controls (299.66,433.8) and (292.18,432.5)..(289.15,434.66) + ..controls (289.73,440.64) and (291.74,441.58)..(295.63,446.62) + ..controls (298.66,452.59) and (297,460.94)..(296.93,468.14) + ..controls (295.49,480.38) and (289.22,487.3)..(289.44,496.44) + ..controls (287.86,495.72) and (286.42,494.57)..(284.26,494.86) + ..controls (283.39,489.46) and (286.42,484.56)..(284.83,480.82) + ..controls (281.95,471.96) and (277.06,446.62)..(279,437.76) + ..controls (280.01,434.74) and (278.21,433.15)..(277.06,433.94) + ..controls (276.77,433.94) and (276.55,433.94)..(276.41,433.94) + ..controls (276.41,433.94) and (276.55,431.42)..(275.69,430.92) + ..controls (274.1,430.34) and (273.67,431.71)..(272.66,432.14) + ..controls (271.22,430.85) and (272.52,429.48)..(271.15,428.04) + ..controls (267.19,428.04) and (261.36,425.38)..(257.98,428.26) + ..controls (257.33,434.16) and (263.3,436.68)..(266.47,440.71) + ..controls (268.63,446.62) and (271.08,462.89)..(267.77,474.62) + ..controls (267.77,475.56) and (264.38,485.28)..(261.43,488.66) + ..controls (258.7,487.66) and (257.33,485.5)..(253.22,486.29) + ..controls (252.58,484.34) and (253.3,482.33)..(252.22,480.1) + ..controls (251.86,479.52) and (249.34,478.58)..(249.19,481.39) + ..controls (248.98,483.05) and (248.9,486.36)..(248.26,486.72) + ..controls (243.65,486.72) and (233.71,487.08)..(231.77,493.92) + ..controls (219.89,492.34) and (215.93,491.26)..(206.57,493.42) + ..controls (196.63,489.67) and (183.24,506.16)..(174.53,502.2) + ..controls (172.51,496.15) and (173.09,485.64)..(171.65,481.39) + ..controls (169.34,474.77) and (171.14,467.14)..(171.14,456.41) + ..controls (170.57,455.4) and (169.85,454.46)..(168.48,454.46) + ..controls (168.48,453.1) and (169.34,450.86)..(168.62,449.42) + ..controls (167.18,447.62) and (165.89,451.8)..(165.02,444.6) + ..controls (163.15,443.74) and (157.75,442.22)..(155.59,445.18) + ..controls (155.88,448.99) and (158.33,451.3)..(160.13,453.38) + ..controls (161.42,456.91) and (160.99,458.28)..(160.7,461.81) + ..controls (160.99,464.98) and (161.71,468.58)..(161.86,470.09) + ..controls (161.86,473.04) and (162.5,479.3)..(161.14,481.18) + --(159.41,482.69)..controls (157.18,487.22) and (158.33,494.64)..(157.61,500.26) + ..controls (155.81,500.69) and (155.81,500.98)..(154.01,498.31) + ..controls (154.01,494.42) and (153.5,486.36)..(152.35,483.84) + ..controls (149.69,479.81) and (150.84,459.65)..(151.42,448.56) + ..controls (151.78,446.47) and (149.69,447.7)..(149.76,444.74) + ..controls (150.05,442.8) and (147.89,443.59)..(146.09,444.6) + ..controls (145.15,445.18) and (146.59,439.78)..(145.37,439.56) + ..controls (142.34,438.84) and (136.87,438.19)..(135.22,440.71) + ..controls (134.57,444.6) and (137.88,448.06)..(140.62,451.01) + ..controls (143.14,455.83) and (140.9,465.7)..(140.47,476.28) + --(138.89,478.22)..controls (134.86,483.19) and (139.61,496.94)..(136.51,506.23) + ..controls (120.02,514.87) and (122.11,519.19)..(118.73,537.62) + ..controls (115.13,557.64) and (93.3799,567.65)..(79.0598,567.65) + ..controls (73.4399,563.04) and (66.24,563.62)..(58.5398,567.65) + ..controls (55.6599,569.23) and (54.4299,573.19)..(54.5,576.5) + ..controls (52.6299,580.75) and (55.22,582.19)..(59.6199,583.49) + ..controls (62.71,587.81) and (68.6199,594.65)..(69.1899,597.74) + ..controls (70.3398,601.92) and (75.5298,608.11)..(77.7598,609.77) + ..controls (75.8198,613.01) and (74.8098,615.17)..(77.1099,618.55) + ..controls (79.5598,620.14) and (81.7898,616.61)..(84.3799,618.55) + --cycle; +pickup pencircle scaled 0bp; +fill (305.28,560.95)..controls (304.63,560.95) and (299.95,561.24)..(299.38,561.24) + ..controls (302.4,550.44) and (303.98,536.47)..(304.2,525.31) + ..controls (303.7,521.35) and (299.81,517.46)..(299.38,525.67) + ..controls (295.85,530.86) and (296.42,540.07)..(293.4,540.29) + ..controls (287.35,539.64) and (285.34,513.22)..(280.01,509.33) + ..controls (276.26,512.28) and (280.73,524.02)..(275.54,524.74) + ..controls (270.5,524.02) and (264.31,526.68)..(266.69,534.46) + ..controls (270.29,543.02) and (268.34,554.76)..(266.54,561.6) + ..controls (262.37,578.59) and (264.02,587.09)..(271.58,596.09) + --(267.48,604.51)..controls (275.4,608.26) and (285.62,604.58)..(290.02,602.21) + ..controls (294.62,600.26) and (300.24,595.94)..(301.1,587.38) + ..controls (303.34,578.88) and (304.42,569.74)..(305.28,560.95) + --cycle; +fill (245.45,600.34)..controls (242.78,599.4) and (239.62,596.02)..(237.67,594.07) + ..controls (236.74,584.42) and (244.58,583.63)..(250.2,577.44) + ..controls (258.77,573.7) and (251.21,567.72)..(256.18,557.42) + ..controls (257.04,550.94) and (257.9,543.89)..(255.31,539.78) + ..controls (249.48,538.92) and (247.97,540.22)..(246.89,531.43) + ..controls (246.31,526.97) and (231.77,529.06)..(229.03,538.27) + ..controls (227.09,544.97) and (221.33,546.7)..(217.8,543.17) + ..controls (213.77,538.06) and (215.78,531.22)..(217.8,527.47) + ..controls (224.93,517.32) and (212.04,511.42)..(205.13,516.74) + ..controls (199.73,508.68) and (211.39,500.04)..(207.43,494.5) + ..controls (205.78,493.99) and (204.77,489.17)..(185.47,500.54) + ..controls (180.36,504.14) and (167.83,500.76)..(168.77,520.63) + ..controls (168.77,525.82) and (165.6,543.53)..(162.14,555.91) + ..controls (159.41,561.24) and (156.74,559.08)..(156.89,553.9) + ..controls (157.18,547.85) and (162.94,531.22)..(155.52,540.22) + ..controls (153.58,539.21) and (156.89,523.58)..(156.89,521.64) + ..controls (162,517.03) and (157.39,513.58)..(154.73,512.28) + ..controls (151.27,518.33) and (149.62,518.04)..(147.17,514.44) + ..controls (141.7,514.08) and (144.58,528.19)..(140.26,528.62) + ..controls (137.02,527.76) and (139.18,520.06)..(138.24,518.76) + ..controls (132.98,524.74) and (130.9,529.27)..(127.01,521.64) + ..controls (126.14,521.64) and (122.11,519.19)..(120.96,526.54) + ..controls (117.65,552.74) and (107.06,558.36)..(93.8198,565.13) + ..controls (92.0198,565.63) and (84.24,566.71)..(79.3398,568.15) + ..controls (73.5098,560.88) and (58.3198,565.63)..(56.23,570.31) + ..controls (54.7898,572.69) and (54.6499,575.21)..(54.7898,576.5) + ..controls (52.3398,580.1) and (55.8699,582.7)..(59.6199,583.06) + ..controls (62.8599,587.16) and (68.5398,594.94)..(71.2798,601.56) + ..controls (72.2898,603.07) and (74.95,609.34)..(78.1899,609.55) + ..controls (74.95,612.94) and (74.2998,622.51)..(82.6599,617.33) + ..controls (87.1199,624.02) and (92.0898,624.31)..(95.7598,615.82) + ..controls (102.89,615.38) and (102.31,608.69)..(115.78,605.52) + ..controls (122.76,602.86) and (132.77,604.58)..(140.26,603.72) + ..controls (136.22,596.88) and (127.44,566.86)..(132.98,559.8) + ..controls (140.76,564.7) and (141.84,605.38)..(157.03,595.66) + ..controls (160.56,593.93) and (159.91,590.04)..(164.09,590.18) + ..controls (170.42,587.45) and (169.13,600.77)..(172.51,600.77) + ..controls (176.47,599.76) and (183.02,599.04)..(186.98,599.54) + ..controls (197.71,600.77) and (206.93,604.08)..(223.92,602.5) + ..controls (231.12,601.78) and (238.25,601.06)..(245.45,600.34) + --cycle; +pickup pencircle scaled 0.636492bp; +draw (305.28,560.95)..controls (304.63,560.95) and (299.95,561.24)..(299.38,561.24) + ..controls (302.4,550.44) and (303.98,536.47)..(304.2,525.31) + ..controls (303.7,521.35) and (299.81,517.46)..(299.38,525.67) + ..controls (295.85,530.86) and (296.42,540.07)..(293.4,540.29) + ..controls (287.35,539.64) and (285.34,513.22)..(280.01,509.33) + ..controls (276.26,512.28) and (280.73,524.02)..(275.54,524.74) + ..controls (270.5,524.02) and (264.31,526.68)..(266.69,534.46) + ..controls (270.29,543.02) and (268.34,554.76)..(266.54,561.6) + ..controls (262.37,578.59) and (264.02,587.09)..(271.58,596.09) + --(267.48,604.51)..controls (275.4,608.26) and (285.62,604.58)..(290.02,602.21) + ..controls (294.62,600.26) and (300.24,595.94)..(301.1,587.38) + ..controls (303.34,578.88) and (304.42,569.74)..(305.28,560.95) + --cycle; +draw (245.45,600.34)..controls (242.78,599.4) and (239.62,596.02)..(237.67,594.07) + ..controls (236.74,584.42) and (244.58,583.63)..(250.2,577.44) + ..controls (258.77,573.7) and (251.21,567.72)..(256.18,557.42) + ..controls (257.04,550.94) and (257.9,543.89)..(255.31,539.78) + ..controls (249.48,538.92) and (247.97,540.22)..(246.89,531.43) + ..controls (246.31,526.97) and (231.77,529.06)..(229.03,538.27) + ..controls (227.09,544.97) and (221.33,546.7)..(217.8,543.17) + ..controls (213.77,538.06) and (215.78,531.22)..(217.8,527.47) + ..controls (224.93,517.32) and (212.04,511.42)..(205.13,516.74) + ..controls (199.73,508.68) and (211.39,500.04)..(207.43,494.5) + ..controls (205.78,493.99) and (204.77,489.17)..(185.47,500.54) + ..controls (180.36,504.14) and (167.83,500.76)..(168.77,520.63) + ..controls (168.77,525.82) and (165.6,543.53)..(162.14,555.91) + ..controls (159.41,561.24) and (156.74,559.08)..(156.89,553.9) + ..controls (157.18,547.85) and (162.94,531.22)..(155.52,540.22) + ..controls (153.58,539.21) and (156.89,523.58)..(156.89,521.64) + ..controls (162,517.03) and (157.39,513.58)..(154.73,512.28) + ..controls (151.27,518.33) and (149.62,518.04)..(147.17,514.44) + ..controls (141.7,514.08) and (144.58,528.19)..(140.26,528.62) + ..controls (137.02,527.76) and (139.18,520.06)..(138.24,518.76) + ..controls (132.98,524.74) and (130.9,529.27)..(127.01,521.64) + ..controls (126.14,521.64) and (122.11,519.19)..(120.96,526.54) + ..controls (117.65,552.74) and (107.06,558.36)..(93.8198,565.13) + ..controls (92.0198,565.63) and (84.24,566.71)..(79.3398,568.15) + ..controls (73.5098,560.88) and (58.3198,565.63)..(56.23,570.31) + ..controls (54.7898,572.69) and (54.6499,575.21)..(54.7898,576.5) + ..controls (52.3398,580.1) and (55.8699,582.7)..(59.6199,583.06) + ..controls (62.8599,587.16) and (68.5398,594.94)..(71.2798,601.56) + ..controls (72.2898,603.07) and (74.95,609.34)..(78.1899,609.55) + ..controls (74.95,612.94) and (74.2998,622.51)..(82.6599,617.33) + ..controls (87.1199,624.02) and (92.0898,624.31)..(95.7598,615.82) + ..controls (102.89,615.38) and (102.31,608.69)..(115.78,605.52) + ..controls (122.76,602.86) and (132.77,604.58)..(140.26,603.72) + ..controls (136.22,596.88) and (127.44,566.86)..(132.98,559.8) + ..controls (140.76,564.7) and (141.84,605.38)..(157.03,595.66) + ..controls (160.56,593.93) and (159.91,590.04)..(164.09,590.18) + ..controls (170.42,587.45) and (169.13,600.77)..(172.51,600.77) + ..controls (176.47,599.76) and (183.02,599.04)..(186.98,599.54) + ..controls (197.71,600.77) and (206.93,604.08)..(223.92,602.5) + ..controls (231.12,601.78) and (238.25,601.06)..(245.45,600.34) + --cycle; +endfig; +end +pstoedit: version 3.18 / DLL interface 106 (build May 1 2000) : Copyright (C) 1993 - 2000 Wolfgang Glunz +Interpreter finished. Return status 0 diff --git a/doc/context/sources/general/manuals/metafun/mycow.pdf b/doc/context/sources/general/manuals/metafun/mycow.pdf Binary files differnew file mode 100644 index 000000000..9cc8fb0b4 --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/mycow.pdf diff --git a/doc/context/sources/general/manuals/metafun/somecow.pdf b/doc/context/sources/general/manuals/metafun/somecow.pdf Binary files differnew file mode 100644 index 000000000..1a43087fd --- /dev/null +++ b/doc/context/sources/general/manuals/metafun/somecow.pdf |