summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/metafun/metafun-examples.tex
diff options
context:
space:
mode:
Diffstat (limited to 'doc/context/sources/general/manuals/metafun/metafun-examples.tex')
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun-examples.tex3269
1 files changed, 3269 insertions, 0 deletions
diff --git a/doc/context/sources/general/manuals/metafun/metafun-examples.tex b/doc/context/sources/general/manuals/metafun/metafun-examples.tex
new file mode 100644
index 000000000..4e5e0eed3
--- /dev/null
+++ b/doc/context/sources/general/manuals/metafun/metafun-examples.tex
@@ -0,0 +1,3269 @@
+% language=uk
+%
+% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa
+
+\startcomponent metafun-examples
+
+\environment metafun-environment
+
+\startchapter[title={A few applications}]
+
+\startintro
+
+For those who need to be inspired, we will demonstrate how \METAPOST\ can be used
+to enhance your document with simple graphics. In these examples we will try to
+be not too clever, simply because we lack the experience to be that clever. The
+real tricks can be found in the files that come with \METAPOST.
+
+\stopintro
+
+\startsection[reference={sec:coils,sec:springs},title={Simple drawings}]
+
+In the words of John Hobby, the creator of \METAPOST, \quotation {\METAPOST\ is
+particularly well||suited for generating figures for technical documents where
+some aspects of a picture may be controlled by mathematical or geometrical
+constraints that are best expressed symbolically. In other words, \METAPOST\ is
+not meant to take the place of a freehand drawing tool or even an interactive
+graphics editor}.
+
+An example of such a picture is the following one, which is dedicated to David
+Arnold, who asked me once how to draw a spring. So, imagine that we want to draw
+a schematic view of a system of four springs.
+
+\startbuffer[a]
+def spring (expr a, b, w, h, n) =
+ ( ( (0,0) -- (0,h) --
+ for i=1 upto n-1: (if odd(i) : - fi w/2,i+h) -- endfor
+ (0,n+h) -- (0,n+2h) )
+ yscaled ((xpart (b-a) ++ ypart (b-a))/(n+2h))
+ rotatedaround(origin,-90+angle(b-a))
+ shifted a )
+enddef ;
+\stopbuffer
+
+\startbuffer[b]
+vardef spring (expr a, b, w, h, n) =
+ pair vec ; path pat ; numeric len ; numeric ang ;
+ vec := (b-a) ;
+ pat := for i=1 upto n-1: (if odd(i):-fi w/2,i)--endfor (0,n) ;
+ pat := (0,0)--(0,h)-- pat shifted (0,h)--(0,n+h)--(0,n+2h) ;
+ len := (xpart vec ++ ypart vec)/(n+2h) ;
+ ang := -90+angle(vec) ;
+ ( pat yscaled len rotatedaround(origin,ang) shifted a )
+enddef ;
+\stopbuffer
+
+\startbuffer[c]
+path p ; p :=
+ (0,0)--spring((.5cm,0),(2.5cm,0),.5cm,0,10)--(3cm,0) ;
+
+draw p withpen pencircle scaled 2pt ;
+draw p withpen pencircle scaled 1pt withcolor .8white;
+\stopbuffer
+
+\startbuffer[d]
+z1 = (+2cm,0) ; z2 = (0,+2cm) ;
+z3 = (-2cm,0) ; z4 = (0,-2cm) ;
+
+pickup pencircle scaled 1.5pt ;
+
+drawoptions (withcolor .625red) ;
+
+draw spring (z1, z2, .75cm, 2, 10) ; draw z1 -- 1.5 z1 ;
+draw spring (z2, z3, .75cm, 2, 9) ; draw z2 -- 1.1 z2 ;
+draw spring (z3, z4, .75cm, 2, 8) ; draw z3 -- 1.5 z3 ;
+draw spring (z4, z1, .75cm, 2, 7) ; draw z4 -- 1.1 z4 ;
+\stopbuffer
+
+\startbuffer[e]
+drawarrow
+ (0,0)--spring((.5cm,0),(2.5cm,0),.5cm,0,10)--(3cm,0)
+ withpen pencircle scaled 2pt withcolor .625red ;
+\stopbuffer
+
+\startbuffer[f]
+numeric u ; u := 1mm ; pickup pencircle scaled (u/2) ;
+drawoptions (withcolor .625red) ;
+draw (0,0)--spring((5u,0),(25u,0),5u,0,10)--(30u,0) ;
+drawoptions (dashed evenly withcolor .5white) ;
+draw (0,0)--spring((5u,0),(35u,0),(25/35)*5u,0,10)--(40u,0) ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,d]
+\stoplinecorrection
+
+A rather natural way to define such a system is:
+
+\typebuffer[d]
+
+Here, the macro \type {spring} takes 5~arguments: two points, the width of the
+winding, the length of the connecting pieces, and the number of elements (half
+windings). The definition of \type {spring} is less complicated than readable.
+
+\typebuffer[a]
+
+First we build a path starting in the origin, going left or right depending on
+the counter being an odd number.
+
+\starttyping
+pat := (0,0) ;
+for i=1 upto n-1:
+ if odd(i) :
+ pat := pat -- (-w/2,i) ;
+ else :
+ pat := pat -- (+w/2,i) ;
+ fi ;
+endfor ;
+pat := pat -- (0,n) ;
+\stoptyping
+
+Once you are accustomed to the way \METAPOST\ interprets (specialists may say
+expand) the source code, you will start using \type {if} and \type {for}
+statements in assignments. The previous code can be converted in a one liner,
+using the pattern:
+
+\starttyping
+pat := for i=1 upto n-1: (x,y)-- endfor (0,n) ;
+\stoptyping
+
+The loop splits out a series of \type {(x,y)--} but the last point is added
+outside the loop. Otherwise \type {pat} would have ended with a dangling \type
+{--}. Of course we need to replace \type {(x,y)} by something meaningful, so we
+get:
+
+\starttyping
+pat := for i=1 upto n-1: (if odd(i):-fi w/2,i)--endfor (0,n) ;
+\stoptyping
+
+We scale this path to the length needed. The expression $b-a$ calculates a
+vector, starting at $a$ and ending at $b$. In \METAPOST, the expression \type
+{a++b} is identical to $\sqrt{a^2+b^2}$. Thus, the expression \typ {xpart (b-a)
+++ ypart (b-a)} calculates the length of the vector $b-a$. Because the unscaled
+spring has length $n+2h$, scaling by the expression \typ {((xpart (b-a) ++ ypart
+(b-a)) / (n+2h))} gives the spring the same length as the vector $b-a$.
+
+Because we have drawn our spring in the vertical position, we first rotate it 90
+degrees clockwise to a horizontal position, and then rotate it through an angle
+equal to the angle in which the vector $b-a$ is pointing. After that, we shift it
+to the first point. The main complications are that we also want to draw
+connecting lines at the beginning and end, as well as support springs that
+connect arbitrary points. Since no check is done on the parameters, you should be
+careful in using this macro.
+
+When we want to improve the readability, we have to use intermediate variables.
+Since the macro is expected to return a path, we must make sure that the content
+matches this expectation.
+
+\typebuffer[b]
+
+If you use \type {vardef}, then the last statement is the return value. Here,
+when \typ {p := spring (z1, z2, .75cm, 2, 10)} is being parsed, the macro is
+expanded, the variables are kept invisible for the assignment, and the path at
+the end is considered to be the return value. In a \type {def} the whole body of
+the macro is \quote {pasted} in the text, while in a \type {vardef} only the last
+line is visible. We will demonstrate this with a simple example.
+
+\starttyping
+def one = (n,n) ; n := n+1 ; enddef ;
+def two = n := n + 1 ; (n,n) enddef ;
+\stoptyping
+
+Now, when we say:
+
+\starttyping
+pair a, b ; numeric n ; n= 10 ; a := one ; b := two ;
+\stoptyping
+
+we definitely get an error message. This is because, when macro \type {two} is
+expanded, \METAPOST\ sees something:
+
+\starttyping
+b := n := n + 1 ;
+\stoptyping
+
+By changing the second definition in
+
+\starttyping
+vardef two = n := n + 1 ; (n,n) enddef ;
+\stoptyping
+
+the increment is expanded out of sight for \type {b :=} and the pair \type
+{(n,n)} is returned.
+
+We can draw a slightly better looking spring by drawing twice with a different
+pen. The following commands use the spring macro implemented by the \type
+{vardef}.
+
+\typebuffer[c]
+
+This time we get:
+
+\startlinecorrection[blank]
+\processMPbuffer[a,c]
+\stoplinecorrection
+
+Since the \type {spring} macro returns a path, you can do whatever is possible
+with a path, like drawing an arrow:
+
+\startlinecorrection[blank]
+\processMPbuffer[a,e]
+\stoplinecorrection
+
+Or even (watch how we use the neutral unit \type {u} to specify the dimensions):
+
+\startlinecorrection[blank]
+\processMPbuffer[a,f]
+\stoplinecorrection
+
+This was keyed in as:
+
+\typebuffer[e]
+
+and:
+
+\typebuffer[f]
+
+\stopsection
+
+\startsection[reference=sec:free labels,title={Free labels}]
+
+\index {labels}
+
+The \METAPOST\ label macro enables you to position text at certain points. This
+macro is kind of special, because it also enables you to influence the
+positioning. For that purpose it uses a special kind of syntax which we will not
+discuss here in detail.
+
+\startbuffer[a]
+pickup pencircle scaled 1mm ;
+path p ; p := fullcircle scaled 3cm ;
+draw p withcolor .625yellow ;
+dotlabel.rt ("right" , point 0 of p) ;
+dotlabel.urt ("upper right" , point 1 of p) ;
+dotlabel.top ("top" , point 2 of p) ;
+dotlabel.ulft ("upper left" , point 3 of p) ;
+dotlabel.lft ("left" , point 4 of p) ;
+dotlabel.llft ("lower left" , point 5 of p) ;
+dotlabel.bot ("bottom" , point 6 of p) ;
+dotlabel.lrt ("lower right" , point 7 of p) ;
+\stopbuffer
+
+\typebuffer[a]
+
+The \type {label} command just typesets a text, while \type {dotlabel} also draws
+a dot at the position of the label. The \type {thelabel} (not shown here) command
+returns a picture.
+
+\startlinecorrection[blank]
+\processMPbuffer[a]
+\stoplinecorrection
+
+There is a numeric constant \type {labeloffset} that can be set to influence the
+distance between the point given and the content of the label. When we set the
+offset to zero, we get the following output.
+
+\startbuffer[x]
+interim labeloffset := 0pt ; % local assignment
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a]
+\stoplinecorrection
+
+This kind of positioning works well as long as we know where we want the label to
+be placed. However, when we place labels automatically, for instance in a macro,
+we have to apply a few clever tricks. There are for sure many ways to accomplish
+this goal, but here we will follow the mathless method.
+
+\startbuffer[a]
+pickup pencircle scaled 1mm ;
+path p ; p := fullcircle scaled 3cm ;
+draw p withcolor .625yellow ;
+vardef do (expr str) =
+ save currentpicture ; picture currentpicture ;
+ currentpicture := thelabel(str,origin) ;
+ draw boundingbox currentpicture withpen pencircle scaled .5pt ;
+ currentpicture
+enddef ;
+\stopbuffer
+
+\startbuffer[b]
+dotlabel.rt (do("right") , point 0 of p) ;
+dotlabel.urt (do("upper right") , point 1 of p) ;
+dotlabel.top (do("top") , point 2 of p) ;
+dotlabel.ulft (do("upper left") , point 3 of p) ;
+dotlabel.lft (do("left") , point 4 of p) ;
+dotlabel.llft (do("lower left") , point 5 of p) ;
+dotlabel.bot (do("bottom") , point 6 of p) ;
+dotlabel.lrt (do("lower right") , point 7 of p) ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+The previous graphic visualizes the bounding box of the labels. This bounding box
+is rather tight and therefore the placement of labels will always be suboptimal.
+Compare the alignment of the left- and rightmost labels. The \type {btex}||\type
+{etex} method is better, since then we can add struts, like:
+
+\starttyping
+btex \strut right etex
+\stoptyping
+
+to force labels with uniform depths and heights. The next graphic demonstrates
+that this looks better indeed. Also, as \TEX\ does the typesetting we get the
+current text font instead of the label font and the content will be properly
+typeset; for instance kerning will be applied when applicable. Spending some time
+on such details pays back in better graphics.
+
+\startbuffer[b]
+dotlabel.rt (do(btex \strut right etex) , point 0 of p) ;
+dotlabel.urt (do(btex \strut upper right etex) , point 1 of p) ;
+dotlabel.top (do(btex \strut top etex) , point 2 of p) ;
+dotlabel.ulft (do(btex \strut upper left etex) , point 3 of p) ;
+dotlabel.lft (do(btex \strut left etex) , point 4 of p) ;
+dotlabel.llft (do(btex \strut lower left etex) , point 5 of p) ;
+dotlabel.bot (do(btex \strut bottom etex) , point 6 of p) ;
+dotlabel.lrt (do(btex \strut lower right etex) , point 7 of p) ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+Now, what happens when we want to place labels in other positions? In the worst
+case, given that we place the labels manually, we end up in vague arguments in
+favour for one or the other placement.
+
+\startbuffer[y]
+p := p rotatedaround(center p, 22.5) ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,y,b]
+\stoplinecorrection
+
+Although any automatic mechanism will be sub||optimal, we can give it a try to
+write a macro that deals with arbitrary locations. This macro will accept three
+arguments and return a picture.
+
+\starttyping
+thefreelabel("some string or picture",a position,the origin)
+\stoptyping
+
+Our testcase is just a simple \type {for} loop that places a series of labels.
+The \type {freedotlabel} macro is derived from \type {thefreelabel}.
+
+\startbuffer[c]
+pickup pencircle scaled 1mm ;
+path p ; p := fullcircle scaled 3cm ;
+draw p withcolor .625yellow ;
+for i=0 step .5 until 7.5 :
+ freedotlabel ("text" , point i of p, center p) ;
+endfor ;
+\stopbuffer
+
+\typebuffer[c]
+
+As a first step we will simply place the labels without any correction. We also
+visualize the bounding box.
+
+\startbuffer[b]
+vardef freedotlabel (expr str, loc, ori) =
+ drawdot loc ; draw thefreelabel(str,loc,ori) ;
+enddef ;
+
+vardef freelabel (expr str, loc, ori) =
+ draw thefreelabel(str,loc,ori) ;
+enddef ;
+\stopbuffer
+
+\startbuffer[a]
+vardef thefreelabel (expr str, loc, ori) =
+ save s ; picture s ; s := thelabel(str,loc) ;
+ draw boundingbox s withpen pencircle scaled .5pt ;
+ s
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+To make our lives more easy, we also define a macro that draws the dot as well as
+a macro that draws the label.
+
+\typebuffer[b]
+
+Now we get:
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b,c]
+\stoplinecorrection
+
+The original label macros permits us to align the label at positions, 4~corners
+and 4~points halfway the sides. It happens that circles are also composed of
+8~points. Because in most cases the label is to be positioned in the direction of
+the center of a curve and the point at hand, it makes sense to take circles as
+the starting points for positioning the labels.
+
+To help us in positioning, we define a special square path, \type {freesquare}.
+This path is constructed out of 8~points that match the positions that are used
+to align labels.
+
+\startbuffer[d]
+path freesquare ;
+
+freesquare := ((-1,0)--(-1,-1)--(0,-1)--(+1,-1)--
+ (+1,0)--(+1,+1)--(0,+1)--(-1,+1)--cycle) scaled .5 ;
+\stopbuffer
+
+\typebuffer[d]
+
+We now show this free path together with a circle, using the following
+definitions:
+
+\startbuffer[e]
+drawpath fullcircle scaled 3cm ;
+drawpoints fullcircle scaled 3cm ;
+drawpointlabels fullcircle scaled 3cm ;
+currentpicture := currentpicture shifted (5cm,0) ;
+drawpath freesquare scaled 3cm ;
+drawpoints freesquare scaled 3cm ;
+drawpointlabels freesquare scaled 3cm ;
+\stopbuffer
+
+\typebuffer[e]
+
+We use two drawing macros that are part of the suite of visual debugging macros.
+
+\startlinecorrection[blank]
+\processMPbuffer[x,d,e]
+\stoplinecorrection
+
+As you can see, point~1 is the corner point that suits best for alignment when a
+label is put at point~1 of the circle. We will now rewrite \type {thefreelabel}
+in such a way that the appropriate point of the associated \type {freesquare} is
+found.
+
+\startbuffer[a]
+vardef thefreelabel (expr str, loc, ori) =
+ save s, p, q, l ; picture s ; path p, q ; pair l ;
+ s := thelabel(str,loc) ;
+ p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
+ q := freesquare xyscaled (urcorner s - llcorner s) ;
+ l := point (xpart (p intersectiontimes (ori--loc))) of q ;
+ draw q shifted loc withpen pencircle scaled .5pt ;
+ draw l shifted loc withcolor .625yellow ;
+ draw loc withcolor .625red ;
+ s
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+The macro xyscaled is part of \METAFUN\ and scales in two directions at once. The
+\METAPOST\ primitive \type {intersectiontimes} returns a pair of time values of
+the point where two paths intersect. The first part of the pair concerns the
+first path.
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b,c]
+\stoplinecorrection
+
+We are now a small step from the exact placement. If we change the last line of
+the macro into:
+
+\starttyping
+(s shifted -l)
+\stoptyping
+
+we get the displacement we want. Although the final look and feel is also
+determined by the text itself, the average result is quite acceptable.
+
+\startbuffer[a]
+vardef thefreelabel (expr str, loc, ori) =
+ save s, p, q, l ; picture s ; path p, q ; pair l ;
+ s := thelabel(str,loc) ;
+ p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
+ q := freesquare xyscaled (urcorner s - llcorner s) ;
+ l := point (xpart (p intersectiontimes (ori--loc))) of q ;
+ draw q shifted loc withpen pencircle scaled .5pt ;
+ draw l shifted loc withcolor .625yellow ;
+ draw loc withcolor .625red ;
+ (s shifted -l)
+enddef ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b,c]
+\stoplinecorrection
+
+Because we also want to pass pictures, and add a bit of offset too, the final
+implementation is slightly more complicated. The picture is handled with an
+additional condition, and the offset with the \METAFUN\ macro \type {enlarged}.
+
+\startbuffer[a]
+newinternal freelabeloffset ; freelabeloffset := 3pt ;
+
+vardef thefreelabel (expr str, loc, ori) =
+ save s, p, q, l ; picture s ; path p, q ; pair l ;
+ interim labeloffset := freelabeloffset ;
+ s := if string str : thelabel(str,loc)
+ else : str shifted -center str shifted loc fi ;
+ setbounds s to boundingbox s enlarged freelabeloffset ;
+ p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
+ q := freesquare xyscaled (urcorner s - llcorner s) ;
+ l := point (xpart (p intersectiontimes (ori--loc))) of q ;
+ setbounds s to boundingbox s enlarged -freelabeloffset ;
+ (s shifted -l)
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+Watch how we temporarily enlarge the bounding box of the typeset label text. We
+will now test this macro on a slightly rotated circle, using labels typeset by
+\TEX. The \type {reverse} is there purely for cosmetic reasons, to suit the label
+texts.
+
+\startbuffer[b]
+pickup pencircle scaled 1mm ;
+path p ; p := reverse fullcircle rotated -25 scaled 3cm ;
+draw p withcolor .625yellow ; pair cp ; cp := center p ;
+freedotlabel (btex \strut We can etex, point 0 of p, cp) ;
+freedotlabel (btex \strut go on etex, point 1 of p, cp) ;
+freedotlabel (btex \strut and on etex, point 2 of p, cp) ;
+freedotlabel (btex \strut in etex, point 3 of p, cp) ;
+freedotlabel (btex \strut defining etex, point 4 of p, cp) ;
+freedotlabel (btex \strut funny etex, point 5 of p, cp) ;
+freedotlabel (btex \strut macros. etex, point 6 of p, cp) ;
+freedotlabel (btex \strut Can't we? etex, point 7 of p, cp) ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b]
+\stoplinecorrection
+
+\typebuffer[b]
+
+Unfortunately we can run into problems due to rounding errors. Therefore we use a
+less readable but more safe expression for calculating the intersection points.
+Instead of using point \type {loc} as endpoint we use \type {loc} shifted over a
+very small distance into the direction \type {loc} from \type{ori}. In the
+assignment to~\type {l} we replace \type {loc} by:
+
+\starttyping
+ ( (1+eps) * arclength(ori--loc) * unitvector(loc-ori) )
+\stoptyping
+
+\stopsection
+
+\startsection[title={Marking angles}]
+
+\index{angles}
+
+A convenient \METAPOST\ macro is \type {unitvector}. When we draw a line segment
+from the origin to the point returned by this macro, the segment has a length of
+1~base point. This macro has a wide range of applications, but some basic
+knowledge of vector algebra is handy. The following lines of \METAPOST\ code
+demonstrate the basics behind unitvectors.
+
+\startbuffer
+pair uv ; pickup pencircle scaled 1mm ; autoarrows := true ;
+draw fullcircle scaled 2cm withcolor .625red ;
+for i=(10,35), (-40,-20), (85,-15) :
+ draw origin--i dashed evenly withcolor .625white ;
+ drawarrow origin--unitvector(i) scaled 1cm withcolor .625yellow ;
+endfor ;
+draw origin withcolor .625red ;
+\stopbuffer
+
+\typebuffer
+
+The circle has a radius of 1cm, and the three line segments are drawn from the
+origin in the direction of the points that are passed as arguments. Because the
+vector has length of~1, we scale it to the radius to let it touch the circle. By
+setting \type {autoarrows} we make sure that the arrowheads are scaled
+proportionally to the linewidth of 1~mm.
+
+\startlinecorrection[blank]
+\processMPbuffer
+\stoplinecorrection
+
+An application of this macro is drawing the angle between two lines. In the
+\METAPOST\ manual you can find two macros for drawing angles: \type {mark_angle}
+and \type {mark_rt_angle}. You may want to take a look at their definitions
+before we start developing our own alternatives.
+
+\startbuffer[x]
+pickup pencircle scaled 1mm ; autoarrows := true ;
+drawoptions(withcolor .625white) ;
+\stopbuffer
+
+\startbuffer[a]
+def anglebetween (expr a, b) =
+ (unitvector(a){a rotated 90} .. unitvector(b))
+enddef ;
+\stopbuffer
+
+\startbuffer[b]
+pair a, b ; a := (2cm,-1cm) ; b := (3cm,1cm) ;
+drawarrow origin--a ; drawarrow origin--b ;
+drawarrow anglebetween(a,b) scaled 1cm withcolor .625red ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+The previous graphic demonstrates what we want to accomplish: a circular curve
+indicating the angle between two straight lines. The lines and curve are drawn
+with the code:
+
+\typebuffer[b]
+
+where \type {anglebetween} is defined as:
+
+\typebuffer[a]
+
+Both unitvectors return just a point on the line positioned 1~unit (later scaled
+to 1cm) from the origin. We connect these points by a curve that starts in the
+direction at the first point. If we omit the \type {a rotated 90} direction
+specifier, we get:
+
+\startbuffer[a]
+def anglebetween (expr a, b) =
+ (unitvector(a) .. unitvector(b))
+enddef ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+These definitions of \type {anglebetween} are far from perfect. If we don't start
+in the origin, we get the curve in the wrong place and when we swap both points,
+we get the wrong curve.
+
+\startbuffer[a]
+def anglebetween (expr endofa, endofb, common, length) =
+ (unitvector (endofa-common){(endofa-common) rotated 90} ..
+ unitvector (endofb-common)) scaled length shifted common
+enddef ;
+\stopbuffer
+
+\startbuffer[b]
+pair a, b, c ; a := (2cm,-1cm) ; b := (3cm,1cm) ; c := (-1cm,.5cm) ;
+drawarrow c--a ; drawarrow c--b ;
+drawarrow anglebetween(a,b,c,1cm) withcolor .625red ;
+\stopbuffer
+
+The solution for the displacement is given in the \METAPOST\ manual and looks
+like this (we package the macro a bit different):
+
+\typebuffer[a]
+
+As you can see, we compensate for the origin of both vectors. This macro is
+called with a few more parameters. We need to pass the length, since we want to
+add the shift to the macro and the shift takes place after the scaling.
+
+\typebuffer[b]
+
+That the results are indeed correct, is demonstrated by the output of following
+example:
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+However, when we swap the points, we get:
+
+\startbuffer[a]
+def anglebetween (expr endofb, endofa, common, length) =
+ (unitvector (endofa-common){(endofa-common) rotated 90} ..
+ unitvector (endofb-common)) scaled length shifted common
+enddef ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+This means that instead of rotating over $90$ degrees, we have to rotate over
+$-90$ or $270$ degrees. That way the arrow will also point in the other
+direction. There are undoubtedly more ways to determine the direction, but the
+following method also demonstrates the use of \type {turningnumber}, which
+reports the direction of a path. For this purpose we compose a dummy cyclic path.
+
+\startbuffer[a]
+vardef anglebetween (expr endofa, endofb, common, length) =
+ save tn ; tn := turningnumber(common--endofa--endofb--cycle) ;
+show tn ;
+ (unitvector(endofa-common){(endofa-common) rotated (tn*90)} ..
+ unitvector(endofb-common)) scaled length shifted common
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+Because we use an intermediate variable, just to keep things readable, we have to
+use \type {vardef} to hide the assignment for the outside world. We demonstrate
+this macro using the following code:
+
+\startbuffer[b]
+pair a, b, c ; a := (2cm,-1cm) ; b := (3cm,1cm) ; c := (-1cm,.5cm) ;
+drawarrow c--a ; drawarrow c--b ;
+drawarrow anglebetween(a,b,c,0.75cm) withcolor .625red ;
+drawarrow anglebetween(b,a,c,1.50cm) withcolor .625red ;
+\stopbuffer
+
+\typebuffer[b]
+
+Watch how both arrows point in the direction of the line that is determined by
+the second point.
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+We now have the framework of an angle drawing macro ready and can start working
+placing the label.
+
+\startbuffer[a]
+vardef anglebetween (expr endofa, endofb, common, length, str) =
+ save curve, where ; path curve ; numeric where ;
+ where := turningnumber (common--endofa--endofb--cycle) ;
+ curve := (unitvector(endofa-common){(endofa-common) rotated (where*90)}
+ .. unitvector(endofb-common)) scaled length shifted common ;
+ draw thefreelabel(str,point .5 of curve,common) withcolor black ;
+ curve
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+The macro \type {thefreelabel} is part of \METAFUN\ and is explained in detail in
+\in {section} [sec:free labels]. This macro tries to place the label as good as
+possible without user interference.
+
+\startbuffer[b]
+pair a ; a := (2cm,-1cm) ; drawarrow origin--a ;
+pair b ; b := (3cm, 1cm) ; drawarrow origin--b ;
+drawarrow
+ anglebetween(a,b,origin,1cm,btex $\alpha$ etex)
+ withcolor .625red ;
+\stopbuffer
+
+\typebuffer[b]
+
+Instead of a picture we may also pass a string, but using \TEX\ by means of \type
+{btex}||\type {etex} often leads to better results.
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+Because in most cases we want the length to be consistent between figures and
+because passing two paths is more convenient than passing three points, the final
+definition looks slightly different.
+
+\startbuffer[a]
+numeric anglelength ; anglelength := 20pt ;
+
+vardef anglebetween (expr a, b, str) = % path path string
+ save endofa, endofb, common, curve, where ;
+ pair endofa, endofb, common ; path curve ; numeric where ;
+ endofa := point length(a) of a ;
+ endofb := point length(b) of b ;
+ if round point 0 of a = round point 0 of b :
+ common := point 0 of a ;
+ else :
+ common := a intersectionpoint b ;
+ fi ;
+ where := turningnumber (common--endofa--endofb--cycle) ;
+ curve := (unitvector (endofa-common){(endofa-common) rotated (where*90)} ..
+ unitvector (endofb-common)) scaled anglelength shifted common ;
+ draw thefreelabel(str,point .5 of curve,common) withcolor black ;
+ curve
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+This macro has a few more \type {if}'s than its predecessor. First we test if the
+label is a string, and if so, we calculate the picture ourselves, otherwise we
+leave this to the user.
+
+\startbuffer[b]
+path a, b, c, d, e, f ;
+a := origin--( 2cm, 1cm) ; b := origin--( 1cm, 2cm) ;
+c := origin--(-2cm, 2cm) ; d := origin--(-2cm,-1cm) ;
+e := origin--(-1cm,-2cm) ; f := origin--( 1cm,-2cm) ;
+for i=a, b, c, d, e, f : drawarrow i ; endfor ;
+anglelength := 1.0cm ; drawoptions(withcolor .625red) ;
+drawarrow anglebetween(a,b,btex $\alpha $ etex) ;
+drawarrow anglebetween(c,d,btex $\gamma $ etex) ;
+drawarrow anglebetween(e,f,btex $\epsilon$ etex) ;
+anglelength := 1.5cm ; drawoptions(withcolor .625yellow) ;
+drawdblarrow anglebetween(b,c,btex $\beta $ etex) ;
+drawarrow reverse anglebetween(d,e,btex $\delta $ etex) ;
+drawarrow anglebetween(a,f,btex $\zeta $ etex) ;
+\stopbuffer
+
+\typebuffer[b]
+
+Because \type {anglebetween} returns a path, you can apply transformations to it,
+like reversing. Close reading of the previous code learns that the macro handles
+both directions.
+
+\startlinecorrection[blank]
+\processMPbuffer[x,a,b]
+\stoplinecorrection
+
+Multiples of 90 degrees are often identified by a rectangular symbol. We will now
+extend the previously defined macro in such a way that more types can be drawn.
+
+\startbuffer[a]
+numeric anglelength ; anglelength := 20pt ;
+numeric anglemethod ; anglemethod := 1 ;
+
+vardef anglebetween (expr a, b, str) = % path path string
+ save pointa, pointb, common, middle, offset ;
+ pair pointa, pointb, common, middle, offset ;
+ save curve ; path curve ;
+ save where ; numeric where ;
+ if round point 0 of a = round point 0 of b :
+ common := point 0 of a ;
+ else :
+ common := a intersectionpoint b ;
+ fi ;
+ pointa := point anglelength on a ;
+ pointb := point anglelength on b ;
+ where := turningnumber (common--pointa--pointb--cycle) ;
+ middle := ((common--pointa) rotatedaround (pointa,-where*90))
+ intersectionpoint
+ ((common--pointb) rotatedaround (pointb, where*90)) ;
+ if anglemethod = 1 :
+ curve := pointa{unitvector(middle-pointa)}.. pointb;
+ middle := point .5 along curve ;
+ elseif anglemethod = 2 :
+ middle := common rotatedaround(.5[pointa,pointb],180) ;
+ curve := pointa--middle--pointb ;
+ elseif anglemethod = 3 :
+ curve := pointa--middle--pointb ;
+ elseif anglemethod = 4 :
+ curve := pointa..controls middle..pointb ;
+ middle := point .5 along curve ;
+ fi ;
+ draw thefreelabel(str, middle, common) withcolor black ;
+ curve
+enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+\startbuffer[p]
+anglemethod := 1 ;
+\stopbuffer
+
+\startbuffer[q]
+anglemethod := 2 ;
+\stopbuffer
+
+\startbuffer[r]
+anglemethod := 3 ;
+\stopbuffer
+
+\startbuffer
+\startcombination[3*1]
+ {\processMPbuffer[x,a,p,b]} {method 1}
+ {\processMPbuffer[x,a,q,b]} {method 2}
+ {\processMPbuffer[x,a,r,b]} {method 3}
+\stopcombination
+\stopbuffer
+
+\placefigure
+ [here][fig:three methods]
+ {Three ways of marking angles.}
+ {\getbuffer}
+
+\in {Figure} [fig:three methods] shows the first three alternative methods
+implemented here. Instead of using \typ {unitvectors}, we now calculate the
+points using the \typ {arctime} and \typ {arclength} primitives. Instead of
+complicated expressions, we use the \METAFUN\ operators \type {along} and \type
+{on}. The following expressions are equivalent.
+
+\starttyping
+pointa := point anglelength on a ;
+middle := point .5 along curve ;
+
+pointa := point (arctime anglelength of a) of a ;
+middle := arctime (.5(arclength curve)) of curve) of curve ;
+\stoptyping
+
+The third method can be implemented in different, more math intensive ways, but
+the current implementation suits rather well and is understood by the author.
+
+\stopsection
+
+\startsection[reference=sec:color circles,title={Color circles}]
+
+\index{color}
+
+In \in {chapter} [sec:embedding] we showed a few color circles. Drawing such a
+graphic can be done in several ways, and here we will show a few methods. First
+we will demonstrate how you can apply \type {cutafter} and \type {cutbefore},
+next we will show how the \METAPOST\ macro \type {buildpath} can be used, and
+finally we will present a clean solution using \type {subpath}. We will assume
+that the circle is called with the macro:
+
+\starttyping
+colorcircle (4cm, red, green, blue) ;
+\stoptyping
+
+\startbuffer[circle]
+vardef colorcircle (expr size, red, green, blue) =
+ save r, g, b, rr, gg, bb, cc, mm, yy ;
+ save b_r, b_g, g_r, g_b ;
+ save radius ;
+
+ path r, g, b, rr, bb, gg, cc, mm, yy ;
+ pair b_r, b_g, g_r, g_b ;
+
+ numeric radius ; radius := 3cm ;
+
+ pickup pencircle scaled (radius/20) ;
+
+ r := g := b := fullcircle scaled radius shifted (0,radius/4);
+
+ r := r rotatedaround(origin, 15) ; % drawarrow r withcolor red ;
+ g := g rotatedaround(origin,135) ; % drawarrow g withcolor green ;
+ b := b rotatedaround(origin,255) ; % drawarrow b withcolor blue ;
+
+ b_r := b intersectionpoint r ; % draw b_r ;
+ b_g := b intersectionpoint g ; % draw b_g ;
+ g_r := reverse g intersectionpoint r ; % draw g_r ;
+ g_b := reverse g intersectionpoint b ; % draw g_b ;
+
+ bb := b cutafter b_r ; bb := bb cutbefore b_g ; % drawarrow bb ;
+ gg := g cutbefore b_g ; gg := gg cutafter g_r ; % drawarrow gg ;
+ rr := r cutbefore g_r & r cutafter b_r ; % drawarrow rr ;
+
+ cc := b cutbefore b_r ; cc := cc cutafter g_b ; % drawarrow br ;
+ yy := g cutbefore g_r ; yy := yy cutafter g_b ; % drawarrow rg ;
+ mm := r cutbefore g_r & r cutafter b_r ; % drawarrow gb ;
+
+ bb := gg -- rr -- reverse bb -- cycle ;
+ gg := bb rotatedaround(origin,120) ;
+ rr := bb rotatedaround(origin,240) ;
+
+ cc := mm -- cc -- reverse yy -- cycle ;
+ yy := cc rotatedaround(origin,120) ;
+ mm := cc rotatedaround(origin,240) ;
+
+ fill fullcircle scaled radius withcolor white ;
+
+ fill rr withcolor red ; fill cc withcolor white-red ;
+ fill gg withcolor green ; fill mm withcolor white-green ;
+ fill bb withcolor blue ; fill yy withcolor white-blue ;
+
+ for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ;
+
+ currentpicture := currentpicture xsized size ;
+enddef ;
+\stopbuffer
+
+We need to calculate seven paths. The first implementation does all the handywork
+itself and thereby is rather long, complicated and unreadable. It does not really
+use the strength of \METAPOST\ yet.
+
+\typebuffer[circle]
+
+In determining the right intersection points, you need to know where the path
+starts and in what direction it moves. In case of doubt, drawing the path as an
+arrow helps. If you want to see the small paths used, you need to comment the
+lines with the \type {fill}'s and uncomment the lines with \type {draw}'s. Due to
+the symmetry and the fact that we keep the figure centered around the origin, we
+only need to calculate two paths since we can rotate them.
+
+There are for sure more (efficient) ways to draw such a figure, but this one
+demonstrates a few new tricks, like grouping. We use grouping here because we
+want to use \type {mm} to indicate the magenta path, and \type {mm} normally
+means millimeter. Within a group, you can save variables. These get their old
+values when the group is left.
+
+With \type {for} we process multiple paths after each other. In this case it
+hardly saves tokens, but it looks more clever.
+
+One of the more efficient methods is using the \type {buildcycle} macro. This
+macro takes two or more paths and calculates the combined path. Although this is
+a rather clever macro, you should be prepared to help it a bit when paths have
+multiple intersection points. Again, we could follow a more secure mathematical
+method, but the next one took only a few minutes of trial and error. To save some
+memory, we redefine the \type {colors} graphic.
+
+\startbuffer[demo]
+colorcircle(4cm, red, green, blue) ;
+\stopbuffer
+
+When we call this macro as:
+
+\typebuffer[demo]
+
+we get:
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+Of course this macro is only used for demonstration purposes and has no real use.
+
+\startbuffer[circle]
+vardef colorcircle (expr size, red, green, blue) =
+ save r, g, b, rr, gg, bb, cc, mm, yy ; save radius ;
+ path r, g, b, rr, bb, gg, cc, mm, yy ; numeric radius ;
+
+ radius := 5cm ; pickup pencircle scaled (radius/25) ;
+
+ r := g := b := fullcircle scaled radius shifted (0,radius/4) ;
+
+ r := r rotatedaround (origin, 15) ;
+ g := g rotatedaround (origin,135) ;
+ b := b rotatedaround (origin,255) ;
+
+ r := r rotatedaround(center r,-90) ;
+ g := g rotatedaround(center g, 90) ;
+
+ gg := buildcycle(buildcycle(reverse r,b),g) ;
+ cc := buildcycle(buildcycle(b,reverse g),r) ;
+
+ rr := gg rotatedaround(origin,120) ;
+ bb := gg rotatedaround(origin,240) ;
+
+ yy := cc rotatedaround(origin,120) ;
+ mm := cc rotatedaround(origin,240) ;
+
+ fill fullcircle scaled radius withcolor white ;
+
+ fill rr withcolor red ; fill cc withcolor white-red ;
+ fill gg withcolor green ; fill mm withcolor white-green ;
+ fill bb withcolor blue ; fill yy withcolor white-blue ;
+
+ for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ;
+
+ currentpicture := currentpicture xsized size ;
+enddef ;
+\stopbuffer
+
+\typebuffer [circle]
+
+Since we don't want to duplicate a graphic, this time we show the dark
+alternatives.
+
+\startbuffer[demo]
+colorcircle(4cm, .5red, .5green, .5blue) ;
+\stopbuffer
+
+\typebuffer[demo]
+
+This kind of unsafe path calculations are very sensitive to breaking. Changing
+the \type {radius/4} into something else demonstrates this but we will not
+challenge this macro that much. Therefore, the 50\% color circle shows up as:
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+This command is part of \METAFUN\ and can be used to determine nice color
+combinations by also looking at their complementary colors.
+
+\startbuffer[demo]
+colorcircle (4cm, .7red, .5green, .3blue) ;
+\stopbuffer
+
+\typebuffer[demo]
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+The next circle that we draw shows the three main colors used in this document.
+This circle is not that beautiful.
+
+\startbuffer[demo]
+colorcircle(4cm,.625red,.625yellow,.625white) ;
+\stopbuffer
+
+\typebuffer[demo]
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+This definition can be cleaned up a bit by using \type {transform}, but the fuzzy
+\type {buildcycle}'s remain.
+
+\startbuffer[circle]
+vardef colorcircle (expr size, red, green, blue) =
+ save r, g, b, rr, gg, bb, cc, mm, yy ; save radius ;
+ path r, g, b, rr, bb, gg, cc, mm, yy ; numeric radius ;
+
+ radius := 5cm ; pickup pencircle scaled (radius/25) ;
+
+ transform t ; t := identity rotatedaround(origin,120) ;
+
+ r := fullcircle scaled radius
+ shifted (0,radius/4) rotatedaround(origin,15) ;
+
+ g := r transformed t ; b := g transformed t ;
+
+ r := r rotatedaround(center r,-90) ;
+ g := g rotatedaround(center g, 90) ;
+
+ gg := buildcycle(buildcycle(reverse r,b),g) ;
+ cc := buildcycle(buildcycle(b,reverse g),r) ;
+
+ rr := gg transformed t ; bb := rr transformed t ;
+ yy := cc transformed t ; mm := yy transformed t ;
+
+ fill fullcircle scaled radius withcolor white ;
+
+ fill rr withcolor red ; fill cc withcolor white-red ;
+ fill gg withcolor green ; fill mm withcolor white-green ;
+ fill bb withcolor blue ; fill yy withcolor white-blue ;
+
+ for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ;
+
+ currentpicture := currentpicture xsized size ;
+enddef ;
+\stopbuffer
+
+\typebuffer [circle]
+
+\startbuffer[demo]
+colorcircle(4cm,(.4,.6,.8),(.8,.4,.6),(.6,.8,.4));
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+This rather nice circle is defined as:
+
+\typebuffer[demo]
+
+The final implementation, which is part of \METAFUN, is slightly more efficient.
+
+\startbuffer[circle]
+vardef colorcircle (expr size, red, green, blue) =
+ save r, g, b, c, m, y, w ; save radius ;
+ path r, g, b, c, m, y, w ; numeric radius ;
+
+ radius := 5cm ; pickup pencircle scaled (radius/25) ;
+
+ transform t ; t := identity rotatedaround(origin,120) ;
+
+ r := fullcircle rotated 90 scaled radius
+ shifted (0,radius/4) rotatedaround(origin,135) ;
+
+ b := r transformed t ; g := b transformed t ;
+
+ c := buildcycle(subpath(1,7) of g, subpath(1,7) of b) ;
+ y := c transformed t ; m := y transformed t ;
+
+ w := buildcycle(subpath(3,5) of r,
+ subpath(3,5) of g, subpath(3,5) of b) ;
+
+ pushcurrentpicture ;
+
+ fill r withcolor red ;
+ fill g withcolor green ;
+ fill b withcolor blue ;
+ fill c withcolor white-red ;
+ fill m withcolor white-green ;
+ fill y withcolor white-blue ;
+ fill w withcolor white ;
+
+ for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ;
+
+ currentpicture := currentpicture xsized size ;
+
+ popcurrentpicture ;
+enddef ;
+\stopbuffer
+
+\typebuffer [circle]
+
+Here, we first fill the primary circles, next we fill the secondary ones. These
+also cover the center, which is why finally we fill the center with white.
+
+\startbuffer[demo]
+colorcircle(4cm,(.2,.5,.8),(.8,.2,.5),(.5,.8,.2));
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+The circle uses the following colors:
+
+\typebuffer[demo]
+
+The next graphic demonstrates how the subpaths look that build the shapes.
+
+\startbuffer[circle]
+vardef colorcircle (expr size, red, green, blue) =
+ save r, g, b, c, m, y, w ; save radius ;
+ path r, g, b, c, m, y, w ; numeric radius ;
+
+ radius := 5cm ; pickup pencircle scaled (radius/25) ;
+
+ transform t ; t := identity rotatedaround(origin,120) ;
+
+ r := fullcircle rotated 90 scaled radius
+ shifted (0,radius/4) rotatedaround(origin,135) ;
+
+ b := r transformed t ; g := b transformed t ;
+
+ c := buildcycle(subpath(1,7) of g,subpath(1,7) of b) ;
+ y := c transformed t ; m := y transformed t ;
+
+ w := buildcycle(subpath(3,5) of r,
+ subpath(3,5) of g, subpath(3,5) of b) ;
+
+ pushcurrentpicture ;
+
+ def do_it =
+ fill r withcolor red ;
+ fill g withcolor green ;
+ fill b withcolor blue ;
+ fill c withcolor white-red ;
+ fill m withcolor white-green ;
+ fill y withcolor white-blue ;
+ fill w withcolor white ;
+ for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ;
+ enddef ;
+
+ autoarrows := true ;
+
+ do_it ;
+ for i=r,g,b : drawarrow i withcolor black ; endfor ;
+ currentpicture := currentpicture shifted (-2radius,0) ;
+
+ do_it ;
+ for i=r,g,b : drawarrow subpath(1,7) of i withcolor black ; endfor ;
+ currentpicture := currentpicture shifted (-2radius,0) ;
+
+ do_it ;
+ for i=r,g,b : drawarrow subpath(3,5) of i withcolor black ; endfor ;
+ currentpicture := currentpicture shifted (+4radius,2radius) ;
+
+ drawarrow r withpen pencircle scaled (radius/10) withcolor red ;
+ drawarrow g withpen pencircle scaled (radius/20) withcolor green ;
+ drawarrow b withpen pencircle scaled (radius/40) withcolor blue ;
+ currentpicture := currentpicture shifted (-2radius,0) ;
+
+ drawarrow c withpen pencircle scaled (radius/10) withcolor white-red ;
+ drawarrow m withpen pencircle scaled (radius/20) withcolor white-green ;
+ drawarrow y withpen pencircle scaled (radius/40) withcolor white-blue ;
+ currentpicture := currentpicture shifted (-2radius,0) ;
+
+ drawarrow w withcolor black ;
+
+ currentpicture := currentpicture xsized 3size ;
+
+ popcurrentpicture ;
+enddef ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[circle,demo]
+\stoplinecorrection
+
+We did not mention what the push and pop commands are responsible for. Scaling
+the current picture is well defined as long as we deal with one graphic. However,
+if the current picture already has some content, this content is also scaled. The
+push and pop commands let us add content to the current picture as well as
+manipulating the picture as a whole without any side effects. The final result is
+put on top of the already drawn content. Instead of the sequence:
+
+\starttyping
+pushcurrentpicture ;
+ ...
+ currentpicture := currentpicture ... transformations ... ;
+popcurrentpicture ;
+\stoptyping
+
+you can say:
+
+\starttyping
+pushcurrentpicture ;
+ ...
+popcurrentpicture ... transformations ... ;
+\stoptyping
+
+Both are equivalent to:
+
+\starttyping
+draw image ( ... ) ... transformations ... ;
+\stoptyping
+
+For larger sequences of commands, the push||pop alternative gives a bit more more
+readable code.
+
+\stopsection
+
+\startsection[title={Fool yourself}]
+
+When doing a literature search on the human perception of black||white edges, I
+ran into several articles with graphics that I remember having seen before in
+books on psychology, physiology and|/|or ergonomics. One of the articles was by
+Edward H.~Adelson of MIT and we will use a few of his example graphics in our
+exploration to what extend \METAPOST\ can be of help in those disciplines. Since
+such graphics normally occur in typeset documents, we will define them in the
+document source.
+
+\startbuffer[a]
+\startbuffer
+interim linecap := butt ; numeric u ; u := 1cm ;
+pickup pencircle scaled .5u ;
+for i=1u step u until 5u :
+ draw (0,i) -- (5u,i) ;
+endfor ;
+for i=2u step u until 4u :
+ draw (u,i) -- (2u,i) withcolor .5white ;
+ draw ((3u,i) -- (4u,i)) shifted (0,-.5u) withcolor .5white ;
+endfor ;
+\stopbuffer
+\stopbuffer
+
+\startbuffer[b]
+\placefigure
+ [here][fig:tricked 1]
+ {White's illusion.}
+ {\processMPbuffer}
+\stopbuffer
+
+\getbuffer[a,b]
+
+Unless you belong to the happy few whose visual capabilities are not distorted by
+neural optimizations, in \in {figure} [fig:tricked 1] the gray rectangles at the
+left look lighter than those on the right. Alas, you can fool yourself, but
+\METAPOST\ does not cheat. This graphic, referred to as White's illusion, is
+defined as follows.
+
+\typebuffer[a]
+
+Watch how we include the code directly. We have packaged this graphic in a buffer
+which we include as a floating figure.
+
+\typebuffer[b]
+
+When passed to \METAPOST, this code is encapsulated in its \type {beginfig} and
+\type {endfig} macros and thereby grouped. But any change to a variable that is
+not explicitly saved, migrates to the outer level. In order to prevent all
+successive graphics to have butt'd linecaps, we have to change this line
+characteristic locally. Because \type {linecap} is defined as an internal
+variable, we have to use \type {interim} to overload its value. Because \type {u}
+is a rather commonly used scratch variable, we don't save its value.
+
+Watch how we use \type {u} as the loop step. In spite of what your eyes tell you,
+this graphic only has two explicit color directives, both being 50\% black. In
+the next example we will use some real colors.
+
+\startbuffer[a]
+\startuseMPgraphic{first}
+ numeric size, delta ;
+ size := 2.5cm ; delta := size/3 ;
+ color mainshade, topshade, bottomshade, centershade ;
+ mainshade := \MPcolor{funcolor} ;
+ topshade := .9mainshade ; bottomshade := .5mainshade ;
+ centershade := .5[topshade,bottomshade] ;
+\stopuseMPgraphic
+\stopbuffer
+
+\startbuffer[b]
+\startuseMPgraphic{second}
+ \includeMPgraphic{first}
+ fill fullsquare scaled size withcolor topshade ;
+ fill fullsquare scaled delta withcolor centershade ;
+\stopuseMPgraphic
+\stopbuffer
+
+\startbuffer[c]
+\startuseMPgraphic{third}
+ \includeMPgraphic{first}
+ fill fullsquare scaled size withcolor bottomshade ;
+ fill fullsquare scaled delta withcolor centershade ;
+\stopuseMPgraphic
+\stopbuffer
+
+\getbuffer[a,b,c]
+
+\startbuffer[d]
+\startcombination[5*2]
+ {\definecolor[funcolor][red] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][green] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][blue] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][yellow]\useMPgraphic{second}} {}
+ {\definecolor[funcolor][white] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][red] \useMPgraphic{third}} {}
+ {\definecolor[funcolor][green] \useMPgraphic{third}} {}
+ {\definecolor[funcolor][blue] \useMPgraphic{third}} {}
+ {\definecolor[funcolor][yellow]\useMPgraphic{third}} {}
+ {\definecolor[funcolor][white] \useMPgraphic{third}} {}
+\stopcombination
+\stopbuffer
+
+\placefigure
+ [here][fig:tricked 2]
+ {The simultaneous contrast effect.}
+ {\getbuffer[d]}
+
+In \in {figure} [fig:tricked 2] the small squares in the center of each colored
+pair of big squares have the same shade, but the way we perceive them are
+influenced by their surroundings. Both sets of squares are defined using usable
+graphics. The top squares are defined as:
+
+\typebuffer[b]
+
+and the bottom squares are coded as:
+
+\typebuffer[c]
+
+Because both graphics share code, we have defined that code as a separate
+graphic, that we include. The only point of interest in this definition is the
+fact that we let \METAPOST\ interpolate between the two colors using \type {.5[
+]}.
+
+\typebuffer[a]
+
+The color \type {funcolor} is provided by \CONTEXT, and since we want to use this
+graphic with different colors, this kind of mapping is quite convenient. The
+bunch of graphics is packaged in a combination with empty captions. Note how we
+set the color before we include the graphic.
+
+\typebuffer[d]
+
+We use a similar arrangement for the following graphic, where we have replaced
+the definitions of \type {first}, \type {second} and \type {third} by new
+definitions.
+
+\startbuffer[a]
+\startuseMPgraphic{first}
+ numeric height, width, radius, gap ; gap := 1mm ;
+ height = 2.5cm ; width := height/2 ; radius := height/2.5 ;
+ color mainshade, leftshade, rightshade, centershade ;
+ mainshade := \MPcolor{funcolor} ;
+ leftshade := .9mainshade ; rightshade := .5mainshade ;
+ centershade := .5[leftshade,rightshade] ;
+ fill unitsquare xyscaled ( width,height) withcolor leftshade ;
+ fill unitsquare xyscaled (-width,height) withcolor rightshade ;
+ draw (fullcircle scaled radius) shifted (0,height/2)
+ withpen pencircle scaled (radius/2) withcolor centershade ;
+\stopuseMPgraphic
+\stopbuffer
+
+\startbuffer[b]
+\startuseMPgraphic{second}
+ \includeMPgraphic{first}
+ interim linecap := butt ; pickup pencircle scaled gap ;
+ draw (0,0) -- (0,height) withcolor white ;
+\stopuseMPgraphic
+\stopbuffer
+
+\startbuffer[c]
+\startuseMPgraphic{third}
+ \includeMPgraphic{first}
+ picture p, q ; p := q := currentpicture ;
+ clip p to unitsquare xscaled width yscaled height ;
+ clip q to unitsquare xscaled -width yscaled height ;
+ currentpicture := p ;
+ addto currentpicture also q shifted (0,radius/2) ;
+\stopuseMPgraphic
+\stopbuffer
+
+\getbuffer[a,b,c]
+
+\startbuffer[d]
+\startcombination[5*3]
+ {\definecolor[funcolor][red] \useMPgraphic{first}} {}
+ {\definecolor[funcolor][green] \useMPgraphic{first}} {}
+ {\definecolor[funcolor][blue] \useMPgraphic{first}} {}
+ {\definecolor[funcolor][yellow]\useMPgraphic{first}} {}
+ {\definecolor[funcolor][white] \useMPgraphic{first}} {}
+ {\definecolor[funcolor][red] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][green] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][blue] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][yellow]\useMPgraphic{second}} {}
+ {\definecolor[funcolor][white] \useMPgraphic{second}} {}
+ {\definecolor[funcolor][red] \useMPgraphic{third}} {}
+ {\definecolor[funcolor][green] \useMPgraphic{third}} {}
+ {\definecolor[funcolor][blue] \useMPgraphic{third}} {}
+ {\definecolor[funcolor][yellow]\useMPgraphic{third}} {}
+ {\definecolor[funcolor][white] \useMPgraphic{third}} {}
+\stopcombination
+\stopbuffer
+
+\placefigure
+ [here][fig:tricked 3]
+ {Koffka's examples of manipulating contrast by changing
+ the spatial configuration.}
+ {\getbuffer[d]}
+
+The definition of the first row of \in {figure} [fig:tricked 3] is used in the
+second and third and therefore is the most complicated. We use quite some scratch
+variables to reach a high level of abstraction. The \type {xyscaled} operator is
+a \METAFUN\ macro.
+
+\typebuffer[a]
+
+The graphics of the second row extends those of the first by drawing a white line
+through the middle. In this example setting the linecap is not really needed,
+because rounded top and bottoms in white are invisible and the part that extends
+beyond the points does not count in calculating the bounding box.
+
+\typebuffer[b]
+
+The third row graphics again extend the first graphic. First we copy the picture
+constructed so far. Watch the double assignment. Next we clip the pictures in
+half, and shift the right half down over the width of the circle.
+
+\typebuffer[c]
+
+\stopsection
+
+% \startsection[title={Puzzles}]
+%
+% {\em Maybe.}
+%
+% \stopsection
+%
+% \startsection[title={Flow charts}]
+%
+% {\em Instead of starting anew every time, you can use predefined macros, like
+% those in the flow chart module. Let's see how we can influence the \METAPOST\
+% code. Maybe not here.}
+%
+% \stopsection
+%
+% \startsection[title={Chemistry}]
+%
+% {\em \METAPOST\ can do it's work unseen, as in the chemistry module that comes
+% with \CONTEXT. There, \METAPOST\ is used as one of the graphical plug||ins. It
+% demonstrates that we can put \METAPOST\ to work without seeing any code.}
+%
+% \stopsection
+
+\startsection[title={Growing graphics}]
+
+Although \METAPOST\ is not really suited as a simulation engine, it is possible
+to build graphics that are built and displayed incrementally with a sequence of
+mouse clicks. The following example is the result of an email discussion David
+Arnold and the author had while \METAFUN\ evolved.
+
+Instead of defining the graphics in a separate \METAPOST\ file, we will
+incorporate them in the document source in which they are used. We can use
+several methods.
+
+\startitemize[n]
+\startitem
+ Define macros and figures in a separate file and include the graphics as
+ external graphics.
+\stopitem
+\startitem
+ Define everything in the document source as usable graphics and include the
+ graphics using \type {\useMPgraphic}.
+\stopitem
+\startitem
+ Package the graphic components in buffers and paste those together as
+ graphics that can be processed at run time.
+\stopitem
+\stopitemize
+
+The first method is the most independent one, which has its advantages if we want
+to use the graphics in other applications too. The second method works well in
+graphics where parts of the definitions change between invocations of the
+graphic. This method follows the template:
+
+\starttyping
+\startuseMPgraphic{whatever}
+ ...
+\stopuseMPgraphic
+
+\startuseMPgraphic{result}
+ ...
+ \includeMPgraphic{whatever}
+ ...
+\stopuseMPgraphic
+
+\useMPgraphic{result}
+\stoptyping
+
+The disadvantage of this method is that it cannot be combined with \type
+{btex}||\type {etex} since it is nearly impossible to determine when, how, and to
+what extent the content of a graphic should be expanded before writing it to the
+temporary \METAPOST\ file.
+
+Therefore, we will demonstrate how buffers can be used. This third method closely
+parallels the first way of defining graphics. A nice side effect is that we can
+easily typeset these buffers verbatim, which we did to typeset this document.
+
+We are going to do a classic compass and straightedge construction, the bisection
+of a line segment joining two arbitrary points. We will construct five graphics,
+where each one displays one step of the construction. We will embed each graphic
+in a start||stop command. Later we will see the advantage of this strategy.
+
+\startbuffer
+\startbuffer[a]
+def start_everything = enddef ;
+def stop_everything = enddef ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startbuffer[b]
+numeric u, w ; u := .5cm ; w := 1pt ;
+
+pickup pencircle scaled w ;
+
+def draw_dot expr p =
+ draw p withpen pencircle scaled 3w ;
+enddef ;
+
+def stand_out =
+ drawoptions(withcolor .625red) ;
+enddef ;
+\stopbuffer
+\stopbuffer
+
+We are going to draw a few dots, and to force consistency we first define a macro
+\type {draw_dot}. The current step will be highlighted in red using \type
+{stand_out}.
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startbuffer[c]
+def draw_basics =
+ pair pointA, pointB ; path lineAB ;
+ pointA := origin ; pointB := pointA shifted (5u,0) ;
+ lineAB := pointA -- pointB ;
+ draw lineAB ;
+ draw_dot pointA ; label.lft(btex A etex, pointA) ;
+ draw_dot pointB ; label.rt (btex B etex, pointB) ;
+enddef ;
+\stopbuffer
+\stopbuffer
+
+First, we construct the macro that will plot two points $A$ and $B$ and connect
+them with a line segment.
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startbuffer[1]
+start_everything ;
+ stand_out ; draw_basics ;
+stop_everything ;
+\stopbuffer
+\stopbuffer
+
+The code in this buffer executes the preceding macros. The \type {..._everything}
+commands are still undefined, but later we can use these hooks for special
+purposes.
+
+\typebuffer \getbuffer
+
+This graphic can now be embedded by the \CONTEXT\ command
+\type {\processMPbuffer}. This command, like the ordinary
+buffer inclusion commands, accepts a list of buffers.
+
+\startbuffer
+\startlinecorrection[blank]
+\ruledhbox{\processMPbuffer[a,b,c,1]}
+\stoplinecorrection
+\stopbuffer
+
+\typebuffer
+
+We use \type {\ruledhbox} to show the tight bounding box of the graphic. The line
+correction takes care of proper spacing around non textual content, like
+graphics. \footnote {These spacing commands try to get the spacing around the
+content visually compatible, and take the height and depth of the preceding and
+following text into account.} This is only needed when the graphic is part of the
+text flow!
+
+\getbuffer
+
+Next, we draw two circles of equal radius, one centered at point $A$, the other
+at point $B$.
+
+\startbuffer
+\startbuffer[d]
+def draw_circles =
+ path circleA, circleB ; numeric radius, distance ;
+ distance := (xpart pointB) - (xpart pointA) ;
+ radius := 2/3 * distance ;
+ circleA := fullcircle scaled (2*radius) ;
+ circleB := circleA shifted pointB ;
+ draw circleA ;
+ draw circleB ;
+enddef ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startbuffer[2]
+start_everything ;
+ draw_basics ; stand_out ; draw_circles ;
+stop_everything ;
+\stopbuffer
+\stopbuffer
+
+As you can see, we move down the \type {stand_out} macro so that only the
+additions are colored red.
+
+\typebuffer \getbuffer
+
+We now use \type{\processMPbuffer[a,b,c,d,2]} to include the latest step.
+
+\startlinecorrection[blank]
+\ruledhbox{\processMPbuffer[a,b,c,d,2]}
+\stoplinecorrection
+
+The next step in the construction of the perpendicular bisector requires that we
+find and label the points of intersection of the two circles centered at points
+$A$ and $B$. The intersection points are calculated as follows. Watch the \type
+{reverse} operation, which makes sure that we get the second intersection point.
+
+\startbuffer
+\startbuffer[e]
+def draw_intersection =
+ pair pointC, pointD ;
+ pointC := circleA intersectionpoint circleB ;
+ pointD := (reverse circleA) intersectionpoint (reverse circleB) ;
+ draw_dot pointC ; label.lft(btex C etex, pointC shifted (-2w,0)) ;
+ draw_dot pointD ; label.lft(btex D etex, pointD shifted (-2w,0)) ;
+enddef ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startbuffer[3]
+start_everything ;
+ draw_basics ; draw_circles ; stand_out ; draw_intersection ;
+stop_everything ;
+\stopbuffer
+\stopbuffer
+
+In placing the label, we must make sure that the text runs free of the lines and
+curves. Again, move the \type {stand_out} macro just prior to \type
+{draw_intersection} macro, so that this step is highlighted in the drawing color,
+while prior steps are drawn in the default color (in this case black).
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\ruledhbox{\processMPbuffer[a,b,c,d,e,3]}
+\stoplinecorrection
+
+The line drawn through points $C$ and $D$ will be the perpendicular bisector of
+the line segment connecting points $A$ and $B$. In the next step we will draw a
+line using the plain \METAPOST\ \type {drawdblarrow} macro that draws arrowheads
+at each end of a path.
+
+\startbuffer
+\startbuffer[f]
+def draw_bisector =
+ path lineCD ;
+ lineCD := origin -- origin shifted (2*distance,0) ;
+ lineCD := lineCD rotated 90 shifted 0.5[pointA,pointB] ;
+ lineCD := lineCD shifted (0,-distance) ;
+ drawdblarrow lineCD ;
+enddef ;
+\stopbuffer
+
+\startbuffer[4]
+start_everything ;
+ draw_basics ; draw_circles ; draw_intersection ; stand_out ;
+ draw_bisector ;
+stop_everything ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\ruledhbox{\processMPbuffer[a,b,c,d,e,f,4]}
+\stoplinecorrection
+
+The following code draws the intersection of line $C-D$ and line segment $A-B$,
+which can be shown to be the midpoint of segment $A-B$.
+
+\startbuffer
+\startbuffer[g]
+def draw_midpoint =
+ pair pointM ;
+ pointM := lineCD intersectionpoint lineAB ;
+ draw_dot pointM ; label.llft(btex M etex, pointM) ;
+enddef ;
+\stopbuffer
+
+\startbuffer[5]
+start_everything ;
+ draw_basics ; draw_circles ; draw_intersection ; draw_bisector ;
+ stand_out ; draw_midpoint ;
+stop_everything ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\ruledhbox{\processMPbuffer[a,b,c,d,e,f,g,5]}
+\stoplinecorrection
+
+As long as we place the graphics as individual insertions in our document,
+everything is fine. However, if we wish to place them all at once, or as we shall
+see later, place them on top of one another in a fieldstack, it makes sense to
+give them all the same bounding box. We can do this by completing the \type
+{start_everything} and \type {stop_everything} commands.
+
+\startbuffer
+\startbuffer[a]
+def start_everything =
+ path bb ;
+ draw_basics ;
+ draw_circles ;
+ draw_intersection ;
+ draw_bisector ;
+ draw_midpoint ;
+ bb := boundingbox currentpicture ;
+ currentpicture := nullpicture ;
+enddef ;
+
+def stop_everything =
+ setbounds currentpicture to bb ;
+enddef ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+In \in {figure} [fig:1 till 5] we demonstrate the effect of this redefinition.
+For this purpose we scale down the graphic to a comfortable 40\%, of course by
+using an additional buffer. We also visualize the bounding box.
+
+\startbuffer
+\startbuffer[h]
+def stop_everything =
+ setbounds currentpicture to bb ;
+ draw bb withpen pencircle scaled .5pt withcolor .625yellow ;
+ currentpicture := currentpicture scaled .4 ;
+enddef ;
+\stopbuffer
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The graphic itself is defined as follows. Watch how we use the default buffer to
+keep the definitions readable.
+
+\startbuffer
+\startbuffer
+\startcombination[5*1]
+ {\processMPbuffer[a,b,c,h,d,e,f,g,1]} {step 1}
+ {\processMPbuffer[a,b,c,h,d,e,f,g,2]} {step 2}
+ {\processMPbuffer[a,b,c,h,d,e,f,g,3]} {step 3}
+ {\processMPbuffer[a,b,c,h,d,e,f,g,4]} {step 4}
+ {\processMPbuffer[a,b,c,h,d,e,f,g,5]} {step 5}
+\stopcombination
+\stopbuffer
+
+\placefigure
+ [here][fig:1 till 5]
+ {The five graphics, each with the same bounding box.}
+ {\getbuffer}
+\stopbuffer
+
+\typebuffer \getbuffer
+
+As the original purpose of these graphics was not to show them side by side, but
+to present them as field stack in a document to be viewed at the computer screen.
+For this purpose we have to define the graphics as symbols.
+
+\startbuffer
+\definesymbol[step 1][{\processMPbuffer[a,b,c,d,e,f,g,1]}]
+\definesymbol[step 2][{\processMPbuffer[a,b,c,d,e,f,g,2]}]
+\definesymbol[step 3][{\processMPbuffer[a,b,c,d,e,f,g,3]}]
+\definesymbol[step 4][{\processMPbuffer[a,b,c,d,e,f,g,4]}]
+\definesymbol[step 5][{\processMPbuffer[a,b,c,d,e,f,g,5]}]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+A field stack is a sequence of overlayed graphics. We will arrange these to cycle
+manually, with clicks of the mouse, through the sequence of graphs depicting the
+construction of the midpoint of segment $A-B$. So, in fact we are dealing with a
+manual simulation. The definition of such a stack is as follows:
+
+\startbuffer
+\definefieldstack
+ [midpoint construction]
+ [step 1, step 2, step 3, step 4, step 5]
+ [frame=on,offset=3pt,framecolor=darkyellow,rulethickness=1pt]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The first argument is to be a unique identifier, the second argument takes a list
+of symbols, while the third argument accepts settings. More on this command can
+be found in the \CONTEXT\ manuals.
+
+The stack is shown as \in {figure} [fig:steps]. Its caption provides a button,
+which enables the reader to cycle through the stack. We call this a stack because
+the graphics are positioned on top of each other. Only one of them is visible at
+any time.
+
+\startbuffer
+\placefigure
+ [here][fig:steps]
+ {Bisecting a line segment with compass and straightedge? Just
+ click \goto {here} [JS(Walk_Field{midpoint construction})] to
+ walk through the construction! (This stack is only visible
+ in a \PDF\ viewer that supports widgets.)}
+ {\framed{\startoverlay
+ {\symbol[step 1]}
+ {\fieldstack[midpoint construction]}
+ \stopoverlay}}
+\stopbuffer
+
+\typebuffer
+
+We cheat a bit and overlay the stack over the first symbol because otherwise
+nothing shows up in print (nowadays I mostly use sumatrapdf).
+
+{\setupinteraction[color=darkred,contrastcolor=darkred]\getbuffer}
+
+At the start of this section, we mentioned three methods. When we use the first
+method of putting all the graphics in an external \METAPOST\ file, the following
+framework suits. We assume that the file is called \type {step.mp} and that it is
+kept by the user along with his document source. We start with the definitions of
+the graphic steps. These are the same as the ones shown previously.
+
+\starttyping
+def draw_basics = ... enddef ;
+def draw_circles = ... enddef ;
+def draw_intersection = ... enddef ;
+def draw_bisector = ... enddef ;
+def draw_midpoint = ... enddef ;
+def stand_out = ... enddef ;
+\stoptyping
+
+We can safe some code by letting the \type {..._everything} take care of the
+\type {beginfig} and \type {endfig} macros.
+
+\starttyping
+def start_everything (expr n) = beginfig(n) ; ... enddef ;
+def stop_everything = ... ; endfig ; enddef ;
+\stoptyping
+
+The five graphics now become:
+
+\starttyping
+start_everything (1) ;
+ stand_out ; draw_basics ;
+stop_everything ;
+
+start_everything (2) ;
+ draw_basics ; stand_out ; draw_circles ;
+stop_everything ;
+
+start_everything (3) ;
+ draw_basics ; draw_circles ; stand_out ; draw_intersection ;
+stop_everything ;
+
+start_everything (4) ;
+ draw_basics ; draw_circles ; draw_intersection ; stand_out ;
+ draw_bisector ;
+stop_everything ;
+
+start_everything (5) ;
+ draw_basics ; draw_circles ; draw_intersection ; draw_bisector ;
+ stand_out ; draw_midpoint ;
+stop_everything ;
+\stoptyping
+
+The definitions of the symbols now refer to an external
+figure.
+
+\starttyping
+\definesymbol[step 1][{\externalfigure[step.1]}]
+\definesymbol[step 2][{\externalfigure[step.2]}]
+\definesymbol[step 3][{\externalfigure[step.3]}]
+\definesymbol[step 4][{\externalfigure[step.4]}]
+\definesymbol[step 5][{\externalfigure[step.5]}]
+\stoptyping
+
+Which method is used, depends on the way the graphics are used. In this example
+we wanted to change the definition of \type {..._everything}, so here the third
+method was quite useful.
+
+\stopsection
+
+\startsection[title={Simple Logos}]
+
+\startbuffer[ns]
+numeric width, height, line, delta ;
+width = 5cm ; height = width/2 ; line = height/4 ; delta = line ;
+
+linejoin := mitered ; pickup pencircle scaled line ;
+
+color nsblue ; nsblue := (0,0,1) ;
+color nsyellow ; nsyellow := (1,1,0) ;
+
+z1 = (0, height/2) ;
+z2 = (width/2-height/4, y1) ;
+z3 = (width/2+height/4, y4) ;
+z4 = (width, 0) ;
+
+z5 = (x4+height/2, y1) ;
+z6 = (x4, 2y1) ;
+z7 = 1.5[z5,z6] ;
+
+path p ; p := z1--z2--z3--z4 ; path q ; q := z3--z4--z5--z7 ;
+
+numeric d, lx, ly, ux, uy ; d = line/2 ;
+
+lx = -3d - d/3 ; ly = -d ; ux = rt x5 + d/3 ; uy = top y6 ;
+
+path r ; r := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle;
+
+lx := lx-delta ; ly := ly-delta ; ux := ux+delta ; uy := uy+delta ;
+
+path s ; s := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle;
+
+draw p withcolor nsblue ; draw q withcolor nsblue ;
+
+addto currentpicture also currentpicture
+ rotatedaround (.5[z2,z3],180) shifted (height/4,height/2) ;
+
+picture savedpicture ; savedpicture := currentpicture ;
+
+clip currentpicture to r ;
+setbounds currentpicture to r ;
+
+savedpicture := currentpicture ; currentpicture := nullpicture ;
+
+fill s withcolor nsyellow ;
+addto currentpicture also savedpicture ;
+\stopbuffer
+
+Many company logos earn their beauty from their simplicity. One of the logos that
+most Dutch people have imprinted in their mind is that of the Dutch Railway
+Company (NS). An interesting feature of this logo is that, although it is widely
+known, drawing it on a piece of paper from mind is a task that many people fail.
+
+\startlinecorrection[blank]
+\processMPbuffer[ns]
+\stoplinecorrection
+
+This logo makes a good candidate for demonstrating a few fine points of drawing
+graphics, like using linear equations, setting line drawing characteristics,
+clipping and manipulating bounding boxes.
+
+The implementation below is quite certainly not according to the official
+specifications, but it can nevertheless serve as an example of defining such
+logos.
+
+\startbuffer[a]
+numeric width ; width = 3cm ;
+numeric height ; height = width/2 ;
+numeric line ; line = height/4 ;
+\stopbuffer
+
+As always, we need to determine the dimensions first. Here, both the height and
+line width depend on the width of the graphic.
+
+Instead of calculating the blue shape such that it will be a filled outline, we
+will draw the logo shape using line segments. This is why we need the \type
+{line} parameter.
+
+\typebuffer[a]
+
+We want sharp corners which can be achieved by setting \type {linejoin} to \type
+{mitered}.
+
+\startbuffer[b]
+linejoin := mitered ; pickup pencircle scaled line ;
+\stopbuffer
+
+\typebuffer[b]
+
+The colors are rather primary blue and yellow. At the time of writing this
+manual, Dutch trains are still painted yellow, so we will use that shade as
+background color.
+
+\startbuffer[c]
+color nsblue ; nsblue := (0,0,1) ;
+color nsyellow ; nsyellow := (1,1,0) ;
+\stopbuffer
+
+\typebuffer[c]
+
+We will now describe the main curves. Although these expressions are not that
+advanced, they demonstrate that we can express relationships instead of using
+assignments.
+
+\startbuffer[d]
+z1 = (0, height/2) ;
+z2 = (width/2-height/4, y1) ;
+z3 = (width/2+height/4, y4) ;
+z4 = (width, 0) ;
+
+path p ; p := z1--z2--z3--z4 ;
+\stopbuffer
+
+\typebuffer[d]
+
+Although it is accepted to consider \type {z} to be a variable, it is in fact a
+\type {vardef} macro, that expands into a pair \type {(x,y)}. This means that the
+previous definitions internally become:
+
+\starttyping
+(x1,y1) = (0, height/2) ;
+(x2,y2) = (width/2-height/4, y1) ;
+(x3,y3) = (width/2+height/4, y4) ;
+(x4,y4) = (width, 0) ;
+\stoptyping
+
+These 8 relations can be solved by \METAPOST, since all dependencies are known.
+
+\starttyping
+x1 = 0 ; y1 = height/2 ;
+x2 = width/2-height/4 ; y2 = y1 ;
+x3 = width/2+height/4 ; y3 = y4 ;
+x4 = width ; y4 = 0 ;
+\stoptyping
+
+Since we express the variables \type {x} and \type {y} in terms of relations, we
+cannot reuse them, because that would mean that inconsistent relations occur. So,
+the following lines will lead to an error message:
+
+\starttyping
+z1 = (10,20) ; z1 = (30,50) ;
+\stoptyping
+
+For similar reasons, we may not assign a value (using \type {:=}) to such a \type
+{z} variable. Within a \METAPOST\ figure, \type {z} variables are automatically
+saved, which means that they can be reused for each figure.
+
+\startbuffer[x]
+drawpath p ; drawpoints p ; drawpointlabels p ;
+\stopbuffer
+
+So far, we have defined the following segment of the logo.
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,x]
+\stoplinecorrection
+
+\startbuffer[e]
+z5 = (x4+height/2, y1) ;
+z6 = (x4, 2y1) ;
+z7 = 1.5[z5,z6] ;
+
+path q ; q := z3--z4--z5--z7 ;
+\stopbuffer
+
+The next expressions are used to define the second segment. The third expression
+determines \type {z7} to be positioned on the line \type {z5--z6}, where we
+extend this line by 50\%.
+
+\typebuffer[e]
+
+\startbuffer[x]
+drawpath q ; drawpoints q ; drawpointlabels q ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,x]
+\stoplinecorrection
+
+If we combine these two segments, we get:
+
+\startbuffer[x]
+drawpath p ; drawpoints p ; drawpointlabels p ;
+swappointlabels := true ;
+drawpath q ; drawpoints q ; drawpointlabels q ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,x]
+\stoplinecorrection
+
+However, when we draw them using the right linewidth and color, you will notice
+that we're not yet done:
+
+\startbuffer[f]
+draw p withcolor nsblue ; draw q withcolor nsblue ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f]
+\stoplinecorrection
+
+The second curve is similar to the first one, but rotated over 180 degrees.
+
+\startbuffer[g]
+addto currentpicture also currentpicture
+ rotatedaround (.5[z2,z3],180) shifted (height/4,height/2) ;
+\stopbuffer
+
+\typebuffer[g]
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f,g]
+\stoplinecorrection
+
+In order to get the sharp edges, we need to clip off part of
+the curves and at first sight, we may consider using a
+scaled bounding box. However, when we show the natural
+bounding box, you will notice that a more complicated bit of
+calculations is needed.
+
+\startbuffer[x]
+draw boundingbox currentpicture
+ withpen pencircle scaled .5mm withcolor .625white ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f,g,x]
+\stoplinecorrection
+
+The right clip path is calculated using the following expressions. Watch how we
+use \type {rt} and \type {top} to correct for the linewidth.
+
+\startbuffer[h]
+numeric d, lx, ly, ux, uy ; d = line/2 ;
+
+lx = -3d - d/3 ; ly = -d ; ux = rt x5 + d/3 ; uy = top y6 ;
+
+path r ; r := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle;
+\stopbuffer
+
+\typebuffer[h]
+
+The clipping path is applied by saying:
+
+\startbuffer[i]
+clip currentpicture to r ;
+\stopbuffer
+
+\typebuffer[i]
+
+The result is quite acceptable:
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f,g,h,i]
+\stoplinecorrection
+
+But, if you watch closely to how this graphic extends into to left margin of this
+document, you will see that the bounding box is not yet right.
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f,g,h,i,x]
+\stoplinecorrection
+
+\startbuffer[j]
+setbounds currentpicture to r ;
+\stopbuffer
+
+\typebuffer[j]
+
+We use the same path \type {r} to correct the bounding box.
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f,g,h,i,j,x]
+\stoplinecorrection
+
+There are a few subtle points involved, like setting the \type {linejoin}
+variable. If we had not set it to \type {mitered}, we would have got round
+corners. We don't set the \type {linecap}, because a flat cap would not extend
+far enough into the touching curve and would have left a small hole. The next
+example shows what happens if we set these variables to the wrong values:
+
+\startbuffer[bb]
+linejoin := rounded ; linecap := mitered ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,bb,c,d,e,f,g,h,i,j]
+\stoplinecorrection
+
+In fact we misuse the fact that both curves overlay each other.
+
+\startbuffer[f]
+draw p withcolor nsblue ; draw q withcolor .625white ;
+\stopbuffer
+
+\startlinecorrection[blank]
+\processMPbuffer[a,b,c,d,e,f,g,h,i,j]
+\stoplinecorrection
+
+The complete logo definition is a bit more extensive because we also want to add
+a background. Because we need to clip the blue foreground graphic, we must
+temporarily store it when we fill the background.
+
+\typebuffer[ns]
+
+For practical use it makes sense to package this definition in a macro to which
+we pass the dimensions.
+
+\stopsection
+
+\startsection[title={Music sheets}]
+
+The next example demonstrates quite some features. Imagine that we want to make
+us a couple of sheets so that we can write a musical masterpiece. Let's also
+forget that \TEX\ can draw lines, which means that somehow we need to use
+\METAPOST.
+
+Drawing a bar is not that complicated as the following code demonstrates.
+
+\startbuffer
+\startusableMPgraphic{bar}
+ vardef MusicBar (expr width, gap, linewidth, barwidth) =
+ image
+ ( interim linecap := butt ;
+ for i=1 upto 5 :
+ draw ((0,0)--(width,0)) shifted (0,(i-1)*gap)
+ withpen pencircle scaled linewidth ;
+ endfor ;
+ for i=llcorner currentpicture -- ulcorner currentpicture ,
+ lrcorner currentpicture -- urcorner currentpicture :
+ draw i withpen pencircle scaled barwidth ;
+ endfor ; )
+ enddef ;
+\stopusableMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+We can define the sidebars a bit more efficient using two predefined subpaths:
+
+\starttyping
+for i=leftboundary currentpicture, rightboundary currentpicture :
+\stoptyping
+
+We define a macro \type {MusicBar} that takes four arguments. The first two
+determine the dimensions, the last two concern the line widths. Now watch how we
+can use this macro:
+
+\startbuffer
+\includeMPgraphic{bar} ;
+draw MusicBar (200pt, 6pt, 1pt, 2pt) ;
+draw MusicBar (300pt, 6pt, 1pt, 2pt) shifted (0,-30pt) ;
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank]
+\processMPbuffer
+\stoplinecorrection
+
+As you can see in this example, the bar is a picture that can be transformed
+(shifted in our case). However, a close look at the macro teaches us that it does
+a couple of draws too. This is possible because we wrap the whole in an image
+using the \type {image} macro. This macro temporary saves the current picture,
+and at the end puts the old \type {currentpicture} under the new one.
+
+We wrap the whole in a \type {vardef}. This means that the image is returned as
+if it was a variable. Actually, the last thing in a \type {vardef} should be a
+proper return value, in our case a picture. This also means that we may not end
+the \type {vardef} with a semi colon. So, when the content of the \type {vardef}
+is expanded, we get something
+
+\starttyping
+draw some_picture ... ;
+\stoptyping
+
+Because we are still drawing something, we can add transform directives and set
+attributes, like the color.
+
+The second \type {for} loop demonstrates two nice features. Instead of repeating
+the draw operation by copying code, we apply it to a list, in our case a list of
+paths. This list contains two simple line paths. Because an \type {image} starts
+with a fresh \type {currentpicture}, we can safely use the bounding box data to
+determine the height of the line.
+
+The next step in producing the sheets of paper is to put several bars on a page,
+preferable with the width of the current text. This time we will use a reusable
+graphic, because each bar is the same.
+
+\startbuffer
+\startreusableMPgraphic{bars}
+ \includeMPgraphic{bar} ;
+ draw MusicBar (TextWidth, 6pt, 1pt, 2pt) withcolor .625yellow ;
+\stopreusableMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\reuseMPgraphic{bars}
+\stoplinecorrection
+
+Instead of going through the trouble of letting \METAPOST\ calculate the positions
+of the bars, we will use \TEX. We put 12 bars on a page and let \TEX\ take care
+of the inter||bar spacing. Because we only want stretchable space between bars,
+called glue in \TEX, we need to remove the last added glue.
+
+\startnotmode[screen]
+
+\startbuffer[music]
+\startstandardmakeup[doublesided=no,page=]
+ \dorecurse{15}{\reuseMPgraphic{bars}\vfill}\removelastskip
+\stopstandardmakeup
+\stopbuffer
+
+\stopnotmode
+
+\startmode[screen]
+
+\startbuffer[music]
+\startstandardmakeup[doublesided=no,page=]
+ \dorecurse{10}{\reuseMPgraphic{bars}\vfill}\removelastskip
+\stopstandardmakeup
+\stopbuffer
+
+\stopmode
+
+\typebuffer[music]
+
+\startusableMPgraphic{bar}
+ vardef MusicBar (expr width, gap, linewidth, barwidth) =
+ image
+ ( interim linecap := butt ;
+ for i=1 upto 5 :
+ draw ((0,0)--(width,0))
+ randomized (1pt,1.5pt)
+ shifted (0,(i-1)*gap)
+ withpen pencircle scaled linewidth ;
+ endfor ;
+ for i=llcorner currentpicture -- ulcorner currentpicture ,
+ lrcorner currentpicture -- urcorner currentpicture :
+ draw i randomized 2pt shifted (0,-1pt)
+ withpen pencircle scaled barwidth ;
+ endfor ; )
+ enddef ;
+\stopusableMPgraphic
+
+\startreusableMPgraphic{bars} % trigger a new one
+ \includeMPgraphic{bar} ;
+ draw MusicBar (TextWidth, 6pt, 1pt, 2pt) withcolor .625yellow ;
+\stopreusableMPgraphic
+
+It may add to the atmosphere of handy||work if you slightly randomize the lines.
+We leave it up to the reader to figure out how the code should be changed to
+accomplish this.
+
+\startlinecorrection[blank]
+\reuseMPgraphic{bars}
+\stoplinecorrection
+
+The complete result is shown on the next page.
+
+\startpostponing
+\getbuffer[music]
+\stoppostponing
+
+\stopsection
+
+\startsection[title={The euro symbol}]
+
+When Patrick Gundlach posted a nice \METAPOST\ version of the euro symbol to the
+\CONTEXT\ discussion list, he added the comment \quotation {The official
+construction is ambiguous: how thick are the horizontal bars? How much do they
+stick out to the left? Is this thing a circle or what? Are the angles on the left
+side of the bars the same as the one on the right side? \unknown} The alternative
+below is probably not as official as his, but permits a finetuning. You are
+warned: whatever you try, the euro {\em is} and {\em will remain} an ugly symbol.
+
+We use a couple of global variables to control the euro shape within reasonable
+bounds. Then we define two circles. Next we define a vertical line that we use in
+a couple of cut and paste operations. Watch how the top left point of the outer
+circle determines the slant of the line that we use to slice the vertical bars.
+
+\startbuffer[euro]
+boolean trace_euro ; trace_euro := false ;
+
+vardef euro_symbol = image ( % begin_of_euro
+
+if unknown euro_radius : euro_radius := 2cm ; fi ;
+if unknown euro_width : euro_width := 3euro_radius/16 ; fi ;
+if unknown euro_r_offset : euro_r_offset := euro_width ; fi ;
+if unknown euro_l_offset : euro_l_offset := euro_radius/32 ; fi ;
+if unknown euro_l_shift : euro_l_shift := euro_r_offset ; fi ;
+if unknown euro_v_delta : euro_v_delta := euro_width/4 ; fi ;
+
+save
+ outer_circle, inner_circle, hor_bar,
+ right_line, right_slant, top_slant, bot_slant,
+ euro_circle, euro_topbar, euro_botbar ;
+
+path
+ outer_circle, inner_circle, hor_bar,
+ right_line, right_slant, top_slant, bot_slant,
+ euro_circle, euro_topbar, euro_botbar ;
+
+outer_circle := fullcircle scaled euro_radius ;
+inner_circle := fullcircle scaled (euro_radius-euro_width) ;
+
+if trace_euro : for i = outer_circle, inner_circle :
+ draw i withpen pencircle scaled 1pt withcolor .5white ;
+endfor ; fi ;
+
+right_line :=
+ (lrcorner outer_circle -- urcorner outer_circle)
+ shifted (-euro_r_offset,0) ;
+
+outer_circle := outer_circle cutbefore right_line ;
+
+right_slant :=
+ point 0 of outer_circle
+ -- origin shifted (0,ypart lrcorner outer_circle) ;
+
+euro_circle := buildcycle(outer_circle, right_line,
+ reverse inner_circle, reverse right_slant) ;
+
+hor_bar := (-euro_radius,0) -- (euro_radius,0) ;
+
+top_slant :=
+ right_slant shifted (-euro_radius+euro_r_offset-euro_l_offset,0) ;
+
+bot_slant :=
+ top_slant shifted (0,-euro_l_shift) ;
+
+if trace_euro : for i = right_line, right_slant, top_slant, bot_slant :
+ draw i withpen pencircle scaled 1pt withcolor .5white ;
+endfor ; fi ;
+
+euro_topbar := buildcycle
+ (top_slant, hor_bar shifted (0, euro_v_delta),
+ right_slant, hor_bar shifted (0, euro_v_delta+euro_width/2)) ;
+
+euro_botbar := buildcycle
+ (bot_slant, hor_bar shifted (0,-euro_v_delta),
+ right_slant, hor_bar shifted (0,-euro_v_delta-euro_width/2)) ;
+
+for i = euro_circle, euro_topbar, euro_botbar :
+ draw i withpen pencircle scaled 0 ;
+endfor ;
+for i = euro_circle, euro_topbar, euro_botbar :
+ fill i withpen pencircle scaled 0 ;
+endfor ;
+
+if trace_euro :
+ drawpoints euro_circle withcolor red ;
+ drawpoints euro_topbar withcolor green ;
+ drawpoints euro_botbar withcolor blue ;
+fi ;
+
+) enddef ; % end_of_euro
+\stopbuffer
+
+\typebuffer[euro]
+
+We only set a parameter when it is not yet set. This has
+the advantage that we don't have to set them when we change
+one. This way of manipulating paths (cutting and building)
+does not always work well because of rounding errors, but
+here it does work.
+
+\startbuffer[demo]
+euro_radius := 4cm ; trace_euro := true ; draw euro_symbol ;
+\stopbuffer
+
+\typebuffer[demo]
+
+For educational purposes, we have added a bit of
+tracing. When enabled, the euro shows up as:
+
+\startlinecorrection[blank]
+\processMPbuffer[euro,demo]
+\stoplinecorrection
+
+Of course it would be best to define the euro as one shape, but we won't go
+though that process right now. By packaging the combined paths in an image, we
+can conveniently color the euro symbol:
+
+\startbuffer[demo]
+draw euro_symbol withcolor .625red ;
+\stopbuffer
+
+\typebuffer[demo]
+
+\startlinecorrection[blank]
+\processMPbuffer[euro,demo]
+\stoplinecorrection
+
+You may wonder why we both draw and fill the euro, using a pen with zero width.
+We've done this in order to demonstrate the \type {redraw} and \type {refill}
+macros.
+
+\startbuffer[extra]
+redraw currentpicture withpen pencircle scaled 4pt withcolor .625yellow ;
+refill currentpicture withcolor .625white ;
+setbounds currentpicture to boundingbox currentpicture enlarged 2pt ;
+\stopbuffer
+
+\typebuffer[extra]
+
+\startlinecorrection[blank]
+\processMPbuffer[euro,demo,extra]
+\stoplinecorrection
+
+\stopsection
+
+\startsection[title={Killing time}]
+
+Not seldom \TEX\ users want to use this program and its meta||relatives as
+general purpose tools, even at the cost of quite some effort or suboptimal
+results. Imagine that you are under way from our planet to Mars. After a long
+period of sleep you wake up and start wondering on what track you are. You even
+start questioning the experts that send you on your way, so you pop open your
+laptop, launch your editor and start metaposting.
+
+First you need to determine the begin and end points of your journey. For now it
+is enough to know the relative angle of the paths that both planets follow as
+well as the path themselves. We assume circular paths.
+
+\startbuffer
+path a ; a := fullcircle scaled 3cm ;
+path b ; b := fullcircle scaled 2cm rotated 120 ;
+
+draw a withpen pencircle scaled 1mm withcolor .625red ;
+draw b withpen pencircle scaled 1mm withcolor .625yellow ;
+
+draw point 0 of a withpen pencircle scaled 2mm ;
+draw point 0 of b withpen pencircle scaled 2mm ;
+\stopbuffer
+
+\typebuffer
+
+The rotation 120 can be calculated from the relative starting points and time the
+journey will take. Alternatively we can use the time along the path, but this
+would be a bit more fuzzy later on. \footnote {In case you wonder why \METAPOST\
+talks about the time on a path, you now have a cue.}
+
+\startlinecorrection[blank]
+\processMPbuffer
+\stoplinecorrection
+
+After a bit of playing with drawing paths between the two points, you decide to
+make a macro. We want to feed the angle between the paths but also the connecting
+path. So, we have to pass a path, but unfortunately we don't have direct access
+to the points. By splitting the argument definition we can pass an expression
+first, and a wildcard argument next.
+
+\startbuffer
+\startuseMPgraphic{gamble}
+def Gamble (expr rot) (text track) =
+ path a ; a := fullcircle scaled 3cm ;
+ path b ; b := fullcircle scaled 2cm rotated rot ;
+
+ pair aa ; aa := point 0 of a ;
+ pair bb ; bb := point 0 of b ;
+ path ab ; ab := track ;
+
+ draw a withpen pencircle scaled 1mm withcolor .625red ;
+ draw b withpen pencircle scaled 1mm withcolor .625yellow ;
+
+ draw aa withpen pencircle scaled 2mm ;
+ draw bb withpen pencircle scaled 2mm ;
+
+ drawarrow ab withpen pencircle scaled 1mm withcolor .625white ;
+
+ setbounds currentpicture to boundingbox a enlarged 2mm ;
+ draw boundingbox currentpicture withpen pencircle scaled .25mm ;
+enddef ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Because at this distance nobody will bother us with the thickness of the pen and
+colors, we code them the hard way. We create our own universe by setting a fixed
+boundingbox.
+
+We leave the Earth in the most popular way, straight upwards and after a few
+cycles, we leave it parallel to the surface. The path drawn reminds much of the
+trajectories shown in popular magazines.
+
+\startbuffer
+\startMPcode
+\includeMPgraphic{gamble} ;
+Gamble(120, aa {(0,1)} .. bb) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+According to \METAPOST, when we leave the Earth straight upwards and want a
+smooth trajectory, we have to pass through outer space.
+
+\startbuffer
+\startMPcode
+\includeMPgraphic{gamble} ;
+Gamble(120,aa {(1,0)} .. bb) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+Given that we want a smooth path as well as a short journey, we can best follow
+Mars' path. Here we face the risk that when we travel slower than Mars does, we
+have a problem.
+
+\startbuffer
+\startMPcode
+\includeMPgraphic{gamble} ;
+Gamble(120,aa {dir 90} .. {precontrol 0 of b rotated 90} bb) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+We can even travel a shorter path when we leave Earth at the surface that faces
+the point of arrival.
+
+\startbuffer
+\startMPcode
+\includeMPgraphic{gamble} ;
+Gamble(120,aa .. {precontrol 0 of b rotated 90} bb) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+In the end we decide that although the trajectories look impressive, we will not
+trust our lives to \METAPOST. A beautiful path is not neccessarily a good path.
+But even then, this macro provides a nice way to experiment with directions,
+controls and tensions.
+
+\stopsection
+
+% \startsection[title={Animations}]
+%
+% {\em Although \METAPOST\ is not that well suited for free hand drawings, you can
+% use it to make stylistics animations.}
+%
+% \stopsection
+
+\startsection[title={Selective randomization}]
+
+In this document we have used a lot of randomization. Because \CONTEXT\ often
+needs multiple runs to sort out cross references, positions, tables of contents,
+and so on, being real random every run would result in endless runs to get things
+right, because the size of graphics changes. This is prevented by storing the
+random seed betweeen runs. You can remove the \type {tuc} file to get a new seed
+(or run \type {context --purgeall}).
+
+Here is another example of randomization. This time we only randomize the control
+points so the main shape sort of remains intact which can be handy when you use
+such random shapes around text but still want a predictable size.
+
+\startbuffer
+\startMPcode
+fill fullcircle scaled 2cm
+ randomizedcontrols 0.1cm
+ withcolor darkred
+ withtransparency (1,.5) ;
+fill ((1cm,0)--(0,1cm)--(-1cm,0)--cycle)
+ randomizedcontrols 0.1cm
+ withcolor darkblue
+ withtransparency (1,.5) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\startbuffer
+\startMPcode
+draw image (
+ fill fullcircle scaled 2cm
+ withcolor darkred
+ withtransparency (1,.5) ;
+ fill ((1cm,0)--(0,1cm)--(-1cm,0)--cycle)
+ withcolor darkblue
+ withtransparency (1,.5) ;
+) randomizedcontrols 0.1cm ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\stopsection
+
+\startsection[title=Snapping]
+
+There are quite some helpers in \METAFUN\ and I must admit that I forgot
+about most. Some just ended up in the core because they can be useful, others
+serve as illustration. Here's one of them: \type {snapped}. First we define
+a few helpers that we then use to check out a few shapes.
+
+\startbuffer
+\startMPdefinitions
+def ShowSnapGrid(text shape) =
+ fill (shape xsized 77mm) withcolor white/3 ;
+ draw image (
+ for i=10mm step 5mm until 100mm :
+ draw fullsquare scaled i ;
+ endfor ;
+ ) withcolor 2white/3 ;
+ drawpoints (shape xsized 77mm) withcolor black ;
+enddef ;
+
+vardef SnapShape expr shape =
+ image (
+ draw shape ;
+ drawpoints shape ;
+ )
+enddef ;
+
+vardef ShowSnapShape expr shape =
+ ShowSnapGrid(shape);
+
+ draw SnapShape(shape xsized 77mm snapped -5mm ) withcolor red ;
+ draw SnapShape(shape xsized 77mm snapped 5mm ) withcolor red ;
+ draw SnapShape(shape xsized 77mm snapped (5mm,10mm)) withcolor green ;
+ draw SnapShape(shape xsized 77mm snapped (5mm,15mm)) withcolor blue ;
+ draw SnapShape(shape xsized 77mm snapped (5mm,20mm)) withcolor yellow ;
+enddef ;
+\stopMPdefinitions
+\stopbuffer
+
+\typebuffer \getbuffer
+
+In \in {figures} [fig:snapper:1], \in [fig:snapper:2] and \in [fig:snapper:3] we
+see how the original shape gets snapped on the grid. Of course in more complex
+images the direction of the snapping can change the result in an unwanted way,
+like overlapping shapes that obscure others, but normally this snapping is only
+useful for simple predictable cases (like title pages).
+
+\startplacefigure[reference=fig:snapper:1,title={Messing with \type{fullcircle}.}]
+\startMPcode
+ ShowSnapShape(fullcircle);
+\stopMPcode
+\stopplacefigure
+
+\startplacefigure[reference=fig:snapper:2,title={\type{fullsquare}}]
+\startMPcode
+ ShowSnapShape(fullsquare);
+\stopMPcode
+\stopplacefigure
+
+\startplacefigure[reference=fig:snapper:3,title={\type{fulltriangle}}]
+\startMPcode
+ ShowSnapShape(fulltriangle);
+\stopMPcode
+\stopplacefigure
+
+\stopsection
+
+\startsection[title=Arrowheads]
+
+Arrows are actually drawn quite well in \METAPOST, as the arrowheads nicely adapt
+to the direction of the point where the arrowhead is attached. There are however
+some limitations as the following examples demonstrate: arrows don't work well
+with transparency and you can probably figure out why. Alan Braslau came up with
+an extension that allows to set the dimple of the head. You can see all this
+in \in {figure} [fig:arrowheads].
+
+\startbuffer[a]
+numeric unit ; unit := mm ;
+
+drawoptions(withcolor .6blue withtransparency (1,.25)) ;
+
+pickup pencircle scaled 2unit ; ahlength := 6unit ;
+
+picture p ; p := image (
+ drawarrow reverse fullcircle rotated - 5 scaled 50unit ;
+ drawarrow reverse fullcircle rotated -10 scaled 30unit ;
+) shifted ( -45unit, 0unit) ;
+
+for i=0 step 90 until 360 : draw p rotated i ; endfor ;
+
+currentpicture := currentpicture shifted - center currentpicture ;
+
+p := currentpicture ; p := image (
+ draw llcorner p -- center p ;
+ drawarrow llcorner p -- 0.875[llcorner p,center p] ;
+) ;
+
+for i=0 step 90 until 360 : draw p rotated i ; endfor ;
+
+clip currentpicture to boundingbox (fullcircle scaled 80unit) ;
+
+if lua.mp.mode("screen") :
+ currentpicture := currentpicture ysized .4TextHeight ;
+else :
+ currentpicture := currentpicture xsized .4TextWidth ;
+fi ;
+\stopbuffer
+
+\typebuffer[a]
+
+\startbuffer[b]
+ resetarrows ;
+\stopbuffer
+
+\startbuffer[a1]
+ ahvariant := 1 ;
+\stopbuffer
+\startbuffer[a2]
+ ahvariant := 2 ;
+\stopbuffer
+
+\startbuffer[a3]
+ ahvariant := 1 ; ahdimple := 1/2 ;
+\stopbuffer
+\startbuffer[a4]
+ ahvariant := 1 ; ahdimple := 1 ;
+\stopbuffer
+\startbuffer[a5]
+ ahvariant := 1 ; ahdimple := 5/2 ;
+\stopbuffer
+
+\startplacefigure[reference=fig:arrowheads,title=The way arrowheads are constructed.]
+ \doifelsemode {screen} {
+ \setupcombination[nx=3,ny=2]
+ } {
+ \setupcombination[nx=2,ny=3]
+ }
+ \startcombination[distance=2em]
+ {\processMPbuffer[a, b]} {\tttf ahvariant=0}
+ {\processMPbuffer[a1,a,b]} {\tttf ahvariant=1}
+ {\processMPbuffer[a2,a,b]} {\tttf ahvariant=2}
+ {\processMPbuffer[a3,a,b]} {\tttf ahvariant=1, ahdimple=1/2}
+ {\processMPbuffer[a4,a,b]} {\tttf ahvariant=1, ahdimple=1}
+ {\processMPbuffer[a5,a,b]} {\tttf ahvariant=1, ahdimple=5/2}
+ \stopcombination
+\stopplacefigure
+
+\stopsection
+
+\startsection[title=Teaser]
+
+Sometimes, when playing with \METAPOST\ you run into interesting cases. Here is
+one. The result is shown in \in {figure} [fig:teaser:1].
+
+\startbuffer
+\startusableMPgraphic{BackgroundTeaser}
+ fill OverlayBox enlarged 1mm withcolor darkyellow ; % bleed
+ path p ; p := OverlayBox enlarged -5mm ;
+ path q ; q := OverlayBox enlarged -10mm ;
+ fill q withcolor white ;
+ drawoptions(withcolor darkred) ;
+ fill reverse topboundary q -- topboundary p -- cycle ;
+ fill reverse bottomboundary q -- bottomboundary p -- cycle ;
+ drawoptions(withcolor darkgreen) ;
+ fill reverse leftboundary q -- leftboundary p -- cycle ;
+ fill reverse rightboundary q -- rightboundary p -- cycle ;
+\stopusableMPgraphic
+
+\defineoverlay
+ [BackgroundTeaser]
+ [\useMPgraphic{BackgroundTeaser}]
+
+\framed
+ [frame=off,
+ offset=15mm,
+ background=BackgroundTeaser,
+ align=normal]
+ {\input knuth }
+\stopbuffer
+
+\typebuffer
+
+\startplacefigure[reference=fig:teaser:1,title=Can you guess what happens here?]
+ \getbuffer
+\stopplacefigure
+
+\stopsection
+
+\startsection[title={Lists}]
+
+For some specific purpose I needed to sort a list of paths and therefore
+\METAFUN\ comes with a quick sort macro. Its working can be demonstrated by an
+example.
+
+\startbuffer[a]
+pair p[], pp[] ; numeric n ; n := 25 ;
+for i=1 upto n : p[i] := origin randomized 4cm ; endfor ;
+\stopbuffer
+
+\startbuffer[b]
+copylist(p,pp) ; % unsorted
+drawarrow listtolines(pp) shifted ( 0,0) withcolor darkblue ;
+\stopbuffer
+
+\startbuffer[c]
+copylist(p,pp) ; sortlist(pp)() ; % sorted
+drawarrow listtolines(pp) shifted (300,0) withcolor darkyellow ;
+\stopbuffer
+
+\startbuffer[d]
+copylist(p,pp) ; sortlist(pp)(xpart) ;
+drawarrow listtolines(pp) shifted (100,0) withcolor darkred ;
+
+\stopbuffer
+\startbuffer[e]
+copylist(p,pp) ; sortlist(pp)(ypart) ;
+drawarrow listtolines(pp) shifted (200,0) withcolor darkgreen ;
+\stopbuffer
+
+\startbuffer[f]
+vardef whow expr p = (xpart p + ypart p) enddef ;
+
+copylist(p,pp) ; sortlist(pp)(whow) ;
+drawarrow listtolines(pp) shifted (400,0) withcolor darkcyan ;
+\stopbuffer
+
+\startbuffer[g]
+vardef whow expr p = (xpart p ++ ypart p) enddef ;
+
+copylist(p,pp) ; sortlist(pp)(whow) ;
+drawarrow listtolines(pp) shifted (500,0) withcolor darkmagenta ;
+\stopbuffer
+
+\typebuffer[a,b,c,d,e,f,g]
+
+The result of this code is shown in \in {figure} [fig:sorting].
+
+\startplacefigure[reference=fig:sorting,title={Using the sorter.}]
+ \startcombination[3*2]
+ {\processMPbuffer[a,b]} {\tttf unsorted}
+ {\processMPbuffer[a,c]} {\tttf sorted}
+ {\processMPbuffer[a,d]} {\tttf xpart}
+ {\processMPbuffer[a,e]} {\tttf ypath}
+ {\processMPbuffer[a,f]} {\tttf xpart p + ypart p}
+ {\processMPbuffer[a,g]} {\tttf xpart p ++ ypart p}
+ \stopcombination
+\stopplacefigure
+
+There is a helper that converts a list of paths into a shape that covers all
+of them. In \in {figure} [fig:shapedlist] three shaped lists are shown.
+
+\startbuffer[a]
+ def ShowShape(expr e) =
+ draw image (
+
+ save p ; path p[] ;
+
+ def MakeShape(expr i,w,h,x,y) =
+ p[i] := e
+ xysized ((w,h) randomized (2mm,1mm))
+ shifted ((x,y) randomized (2mm,1mm)) ;
+ enddef ;
+
+ MakeShape(1,40mm,6mm,10mm, 0mm) ;
+ MakeShape(2,50mm,5mm, 5mm,-10mm) ;
+ MakeShape(3,20mm,8mm,30mm,-20mm) ;
+ MakeShape(4,55mm,5mm,10mm,-30mm) ;
+ MakeShape(5,55mm,5mm, 5mm,-50mm) ;
+
+ save s ; path s ; s := shapedlist(p) ; drawarrow s ;
+
+ linejoin := butt ;
+
+ for i=1 upto 5 :
+ fill p[i] withcolor .75white withtransparency (1,.5) ;
+ draw thetextext("\tttf " & decimal i, center p[i]) ;
+ endfor ;
+
+ ) ysized 4cm ;
+ enddef ;
+\stopbuffer
+
+\typebuffer[a]
+
+\startbuffer[b]
+ShowShape(unitsquare)
+\stopbuffer
+
+\startbuffer[c]
+ShowShape(unitcircle)
+\stopbuffer
+
+\startbuffer[d]
+ShowShape(unittriangle)
+\stopbuffer
+
+\startplacefigure[reference=fig:shapedlist,title={The \type {shapedlist} macro returns the envelope that covers all the paths in the list.}]
+ \startcombination[3*1]
+ {\processMPbuffer[a,b]} {\tttf unitsquare}
+ {\processMPbuffer[a,c]} {\tttf unitcircle}
+ {\processMPbuffer[a,d]} {\tttf unittriangle}
+ \stopcombination
+\stopplacefigure
+
+\stopsection
+
+\startsection[title=Table cells]
+
+Sometimes a standard \CONTEXT\ feature doesn't work out as expected. Take the
+following table:
+
+\startbuffer
+\bTABLE[frame=on,framecolor=blue,rulethickness=1pt]
+ \bTR
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD[framecolor=magenta] test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \eTR
+ \bTR
+ \bTD test \eTD
+ \bTD[framecolor=red] test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD[framecolor=green] test \eTD
+ \eTR
+\eTABLE
+\stopbuffer
+
+\typebuffer
+
+Because cells are drawn top|-|down and left|-|right a next cell border
+overruns the previous one.
+
+\startlinecorrection
+\getbuffer
+\stoplinecorrection
+
+\startbuffer
+\bTABLE[frame=on,framecolor=blue,rulethickness=1pt]
+ \bTR
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD[framecolor=magenta,frameoffset=-.5pt] test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \eTR
+ \bTR
+ \bTD test \eTD
+ \bTD[framecolor=red,frameoffset=-.5pt] test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD[framecolor=green,frameoffset=-.5pt] test \eTD
+ \eTR
+\eTABLE
+\stopbuffer
+
+You can try this:
+
+\typebuffer
+
+which gives us something that is not okay either for cells that touch an edge:
+
+\startlinecorrection
+\getbuffer
+\stoplinecorrection
+
+but we can cheat:
+
+\startlinecorrection
+\framed
+ [offset=overlay,
+ frameoffset=.5pt,
+ framecolor=blue,
+ rulethickness=1pt]
+ {\getbuffer}
+\stoplinecorrection
+
+This is achieved by framing the whole table:
+
+\starttyping
+\framed
+ [offset=overlay,
+ frameoffset=.5pt,
+ framecolor=blue,
+ rulethickness=1pt]
+ {...}
+\stoptyping
+
+\startbuffer
+\startuseMPgraphic{cell:innerframe}{innercolor}
+ draw OverlayBox enlarged -1.5OverlayLineWidth
+ withpen pensquare scaled OverlayLineWidth
+ withcolor \MPvar{innercolor} ;
+\stopuseMPgraphic
+
+\defineoverlay
+ [innerframe]
+ [{\uniqueMPgraphic{cell:innerframe}%
+ {innercolor=\framedparameter{innercolor}}}]
+
+\bTABLE[frame=on,framecolor=blue,rulethickness=1pt,innercolor=magenta]
+ \bTR
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD[background=innerframe] test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \eTR
+ \bTR
+ \bTD test \eTD
+ \bTD[background=innerframe,innercolor=red] test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD test \eTD
+ \bTD[background=innerframe,innercolor=green] test \eTD
+ \eTR
+\eTABLE
+\stopbuffer
+
+A \METAPOST\ alternative is also possible and it gives a bit nicer
+interface too:
+
+\typebuffer
+
+We get:
+
+\startlinecorrection
+\getbuffer
+\stoplinecorrection
+
+\stopsection
+
+\stopchapter
+
+\stopcomponent