diff options
Diffstat (limited to 'doc/context/sources/general/manuals/metafun/metafun-basics.tex')
-rw-r--r-- | doc/context/sources/general/manuals/metafun/metafun-basics.tex | 3587 |
1 files changed, 3587 insertions, 0 deletions
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 |