metafun-examples.tex /size: 107 Kb    last modification: 2023-12-21 09:43
1% language=us runpath=texruns:manuals/metafun
2
3\startcomponent metafun-examples
4
5\environment metafun-environment
6
7\startchapter[title={A few applications}]
8
9\startintro
10
11For those who need to be inspired, we will demonstrate how \METAPOST\ can be used
12to enhance your document with simple graphics. In these examples we will try to
13be not too clever, simply because we lack the experience to be that clever. The
14real tricks can be found in the files that come with \METAPOST.
15
16\stopintro
17
18\startsection[reference={sec:coils,sec:springs},title={Simple drawings}]
19
20In the words of John Hobby, the creator of \METAPOST, \quotation {\METAPOST\ is
21particularly well||suited for generating figures for technical documents where
22some aspects of a picture may be controlled by mathematical or geometrical
23constraints that are best expressed symbolically. In other words, \METAPOST\ is
24not meant to take the place of a freehand drawing tool or even an interactive
25graphics editor}.
26
27An example of such a picture is the following one, which is dedicated to David
28Arnold, who asked me once how to draw a spring. So, imagine that we want to draw
29a schematic view of a system of four springs.
30
31\startbuffer[a]
32def spring (expr a, b, w, h, n) =
33  ( ( (0,0) -- (0,h) --
34      for i=1 upto n-1: (if odd(i) : - fi w/2,i+h) -- endfor
35      (0,n+h) -- (0,n+2h) )
36    yscaled ((xpart (b-a) ++ ypart (b-a))/(n+2h))
37    rotatedaround(origin,-90+angle(b-a))
38    shifted a )
39enddef ;
40\stopbuffer
41
42\startbuffer[b]
43vardef spring (expr a, b, w, h, n) =
44  pair vec ; path pat ; numeric len ; numeric ang ;
45  vec := (b-a) ;
46  pat := for i=1 upto n-1: (if odd(i):-fi w/2,i)--endfor (0,n) ;
47  pat := (0,0)--(0,h)-- pat shifted (0,h)--(0,n+h)--(0,n+2h) ;
48  len := (xpart vec ++ ypart vec)/(n+2h) ;
49  ang := -90+angle(vec) ;
50  ( pat yscaled len rotatedaround(origin,ang) shifted a )
51enddef ;
52\stopbuffer
53
54\startbuffer[c]
55path p ; p :=
56  (0,0)--spring((.5cm,0),(2.5cm,0),.5cm,0,10)--(3cm,0) ;
57
58draw p withpen pencircle scaled 2pt ;
59draw p withpen pencircle scaled 1pt withcolor .8white;
60\stopbuffer
61
62\startbuffer[d]
63z1 = (+2cm,0) ; z2 = (0,+2cm) ;
64z3 = (-2cm,0) ; z4 = (0,-2cm) ;
65
66pickup pencircle scaled 1.5pt ;
67
68drawoptions (withcolor .625red) ;
69
70draw spring (z1, z2, .75cm, 2, 10) ; draw z1 -- 1.5 z1 ;
71draw spring (z2, z3, .75cm, 2,  9) ; draw z2 -- 1.1 z2 ;
72draw spring (z3, z4, .75cm, 2,  8) ; draw z3 -- 1.5 z3 ;
73draw spring (z4, z1, .75cm, 2,  7) ; draw z4 -- 1.1 z4 ;
74\stopbuffer
75
76\startbuffer[e]
77drawarrow
78  (0,0)--spring((.5cm,0),(2.5cm,0),.5cm,0,10)--(3cm,0)
79  withpen pencircle scaled 2pt withcolor .625red ;
80\stopbuffer
81
82\startbuffer[f]
83numeric u ; u := 1mm ; pickup pencircle scaled (u/2) ;
84drawoptions (withcolor .625red) ;
85draw (0,0)--spring((5u,0),(25u,0),5u,0,10)--(30u,0) ;
86drawoptions (dashed evenly withcolor .5white) ;
87draw (0,0)--spring((5u,0),(35u,0),(25/35)*5u,0,10)--(40u,0) ;
88\stopbuffer
89
90\startlinecorrection[blank]
91\processMPbuffer[a,d]
92\stoplinecorrection
93
94A rather natural way to define such a system is:
95
96\typebuffer[d]
97
98Here, the macro \type {spring} takes 5~arguments: two points, the width of the
99winding, the length of the connecting pieces, and the number of elements (half
100windings). The definition of \type {spring} is less complicated than readable.
101
102\typebuffer[a]
103
104First we build a path starting in the origin, going left or right depending on
105the counter being an odd number.
106
107\starttyping
108pat := (0,0) ;
109for i=1 upto n-1:
110  if odd(i) :
111    pat := pat -- (-w/2,i) ;
112  else :
113    pat := pat -- (+w/2,i) ;
114  fi ;
115endfor ;
116pat := pat -- (0,n) ;
117\stoptyping
118
119Once you are accustomed to the way \METAPOST\ interprets (specialists may say
120expand) the source code, you will start using \type {if} and \type {for}
121statements in assignments. The previous code can be converted in a one liner,
122using the pattern:
123
124\starttyping
125pat := for i=1 upto n-1: (x,y)-- endfor (0,n) ;
126\stoptyping
127
128The loop splits out a series of \type {(x,y)--} but the last point is added
129outside the loop. Otherwise \type {pat} would have ended with a dangling \type
130{--}. Of course we need to replace \type {(x,y)} by something meaningful, so we
131get:
132
133\starttyping
134pat := for i=1 upto n-1: (if odd(i):-fi w/2,i)--endfor (0,n) ;
135\stoptyping
136
137We scale this path to the length needed. The expression $b-a$ calculates a
138vector, starting at $a$ and ending at $b$. In \METAPOST, the expression \type
139{a++b} is identical to $\sqrt{a^2+b^2}$. Thus, the expression \typ {xpart (b-a)
140++ ypart (b-a)} calculates the length of the vector $b-a$. Because the unscaled
141spring has length $n+2h$, scaling by the expression \typ {((xpart (b-a) ++ ypart
142(b-a)) / (n+2h))} gives the spring the same length as the vector $b-a$.
143
144Because we have drawn our spring in the vertical position, we first rotate it 90
145degrees clockwise to a horizontal position, and then rotate it through an angle
146equal to the angle in which the vector $b-a$ is pointing. After that, we shift it
147to the first point. The main complications are that we also want to draw
148connecting lines at the beginning and end, as well as support springs that
149connect arbitrary points. Since no check is done on the parameters, you should be
150careful in using this macro.
151
152When we want to improve the readability, we have to use intermediate variables.
153Since the macro is expected to return a path, we must make sure that the content
154matches this expectation.
155
156\typebuffer[b]
157
158If you use \type {vardef}, then the last statement is the return value. Here,
159when \typ {p := spring (z1, z2, .75cm, 2, 10)} is being parsed, the macro is
160expanded, the variables are kept invisible for the assignment, and the path at
161the end is considered to be the return value. In a \type {def} the whole body of
162the macro is \quote {pasted} in the text, while in a \type {vardef} only the last
163line is visible. We will demonstrate this with a simple example.
164
165\starttyping
166def one = (n,n) ; n := n+1 ; enddef ;
167def two = n := n + 1 ; (n,n) enddef ;
168\stoptyping
169
170Now, when we say:
171
172\starttyping
173pair a, b ; numeric n ; n= 10 ; a := one ; b := two ;
174\stoptyping
175
176we definitely get an error message. This is because, when macro \type {two} is
177expanded, \METAPOST\ sees something:
178
179\starttyping
180b := n := n + 1 ;
181\stoptyping
182
183By changing the second definition in
184
185\starttyping
186vardef two = n := n + 1 ; (n,n) enddef ;
187\stoptyping
188
189the increment is expanded out of sight for \type {b :=} and the pair \type
190{(n,n)} is returned.
191
192We can draw a slightly better looking spring by drawing twice with a different
193pen. The following commands use the spring macro implemented by the \type
194{vardef}.
195
196\typebuffer[c]
197
198This time we get:
199
200\startlinecorrection[blank]
201\processMPbuffer[a,c]
202\stoplinecorrection
203
204Since the \type {spring} macro returns a path, you can do whatever is possible
205with a path, like drawing an arrow:
206
207\startlinecorrection[blank]
208\processMPbuffer[a,e]
209\stoplinecorrection
210
211Or even (watch how we use the neutral unit \type {u} to specify the dimensions):
212
213\startlinecorrection[blank]
214\processMPbuffer[a,f]
215\stoplinecorrection
216
217This was keyed in as:
218
219\typebuffer[e]
220
221and:
222
223\typebuffer[f]
224
225\stopsection
226
227\startsection[reference=sec:free labels,title={Free labels}]
228
229\index {labels}
230
231The \METAPOST\ label macro enables you to position text at certain points. This
232macro is kind of special, because it also enables you to influence the
233positioning. For that purpose it uses a special kind of syntax which we will not
234discuss here in detail.
235
236\startbuffer[a]
237pickup pencircle scaled 1mm ;
238path p ; p := fullcircle scaled 3cm ;
239draw p withcolor .625yellow ;
240dotlabel.rt   ("right"       , point 0 of p) ;
241dotlabel.urt  ("upper right" , point 1 of p) ;
242dotlabel.top  ("top"         , point 2 of p) ;
243dotlabel.ulft ("upper left"  , point 3 of p) ;
244dotlabel.lft  ("left"        , point 4 of p) ;
245dotlabel.llft ("lower left"  , point 5 of p) ;
246dotlabel.bot  ("bottom"      , point 6 of p) ;
247dotlabel.lrt  ("lower right" , point 7 of p) ;
248\stopbuffer
249
250\typebuffer[a]
251
252The \type {label} command just typesets a text, while \type {dotlabel} also draws
253a dot at the position of the label. The \type {thelabel} (not shown here) command
254returns a picture.
255
256\startlinecorrection[blank]
257\processMPbuffer[a]
258\stoplinecorrection
259
260There is a numeric constant \type {labeloffset} that can be set to influence the
261distance between the point given and the content of the label. When we set the
262offset to zero, we get the following output.
263
264\startbuffer[x]
265interim labeloffset := 0pt ; % local assignment
266\stopbuffer
267
268\startlinecorrection[blank]
269\processMPbuffer[x,a]
270\stoplinecorrection
271
272This kind of positioning works well as long as we know where we want the label to
273be placed. However, when we place labels automatically, for instance in a macro,
274we have to apply a few clever tricks. There are for sure many ways to accomplish
275this goal, but here we will follow the mathless method.
276
277\startbuffer[a]
278pickup pencircle scaled 1mm ;
279path p ; p := fullcircle scaled 3cm ;
280draw p withcolor .625yellow ;
281vardef do (expr str) =
282  save currentpicture ; picture currentpicture ;
283  currentpicture := thelabel(str,origin) ;
284  draw boundingbox currentpicture withpen pencircle scaled .5pt ;
285  currentpicture
286enddef ;
287\stopbuffer
288
289\startbuffer[b]
290dotlabel.rt   (do("right")       , point 0 of p) ;
291dotlabel.urt  (do("upper right") , point 1 of p) ;
292dotlabel.top  (do("top")         , point 2 of p) ;
293dotlabel.ulft (do("upper left")  , point 3 of p) ;
294dotlabel.lft  (do("left")        , point 4 of p) ;
295dotlabel.llft (do("lower left")  , point 5 of p) ;
296dotlabel.bot  (do("bottom")      , point 6 of p) ;
297dotlabel.lrt  (do("lower right") , point 7 of p) ;
298\stopbuffer
299
300\startlinecorrection[blank]
301\processMPbuffer[x,a,b]
302\stoplinecorrection
303
304The previous graphic visualizes the bounding box of the labels. This bounding box
305is rather tight and therefore the placement of labels will always be suboptimal.
306Compare the alignment of the left- and rightmost labels. The \type {btex}||\type
307{etex} method is better, since then we can add struts, like:
308
309\starttyping
310btex \strut right etex
311\stoptyping
312
313to force labels with uniform depths and heights. The next graphic demonstrates
314that this looks better indeed. Also, as \TEX\ does the typesetting we get the
315current text font instead of the label font and the content will be properly
316typeset; for instance kerning will be applied when applicable. Spending some time
317on such details pays back in better graphics.
318
319\startbuffer[b]
320dotlabel.rt   (do(btex \strut right       etex) , point 0 of p) ;
321dotlabel.urt  (do(btex \strut upper right etex) , point 1 of p) ;
322dotlabel.top  (do(btex \strut top         etex) , point 2 of p) ;
323dotlabel.ulft (do(btex \strut upper left  etex) , point 3 of p) ;
324dotlabel.lft  (do(btex \strut left        etex) , point 4 of p) ;
325dotlabel.llft (do(btex \strut lower left  etex) , point 5 of p) ;
326dotlabel.bot  (do(btex \strut bottom      etex) , point 6 of p) ;
327dotlabel.lrt  (do(btex \strut lower right etex) , point 7 of p) ;
328\stopbuffer
329
330\startlinecorrection[blank]
331\processMPbuffer[x,a,b]
332\stoplinecorrection
333
334Now, what happens when we want to place labels in other positions? In the worst
335case, given that we place the labels manually, we end up in vague arguments in
336favour for one or the other placement.
337
338\startbuffer[y]
339p := p rotatedaround(center p, 22.5) ;
340\stopbuffer
341
342\startlinecorrection[blank]
343\processMPbuffer[x,a,y,b]
344\stoplinecorrection
345
346Although any automatic mechanism will be sub||optimal, we can give it a try to
347write a macro that deals with arbitrary locations. This macro will accept three
348arguments and return a picture.
349
350\starttyping
351thefreelabel("some string or picture",a position,the origin)
352\stoptyping
353
354Our testcase is just a simple \type {for} loop that places a series of labels.
355The \type {freedotlabel} macro is derived from \type {thefreelabel}.
356
357\startbuffer[c]
358pickup pencircle scaled 1mm ;
359path p ; p := fullcircle scaled 3cm ;
360draw p withcolor .625yellow ;
361for i=0 step .5 until 7.5 :
362  freedotlabel ("text" , point i of p, center p) ;
363endfor ;
364\stopbuffer
365
366\typebuffer[c]
367
368As a first step we will simply place the labels without any correction. We also
369visualize the bounding box.
370
371\startbuffer[b]
372vardef freedotlabel (expr str, loc, ori) =
373  drawdot loc ; draw thefreelabel(str,loc,ori) ;
374enddef ;
375
376vardef freelabel (expr str, loc, ori) =
377  draw thefreelabel(str,loc,ori) ;
378enddef ;
379\stopbuffer
380
381\startbuffer[a]
382vardef thefreelabel (expr str, loc, ori) =
383  save s ; picture s ; s := thelabel(str,loc) ;
384  draw boundingbox s withpen pencircle scaled .5pt ;
385  s
386enddef ;
387\stopbuffer
388
389\typebuffer[a]
390
391To make our lives more easy, we also define a macro that draws the dot as well as
392a macro that draws the label.
393
394\typebuffer[b]
395
396Now we get:
397
398\startlinecorrection[blank]
399\processMPbuffer[x,a,b,c]
400\stoplinecorrection
401
402The original label macros permits us to align the label at positions, 4~corners
403and 4~points halfway the sides. It happens that circles are also composed of
4048~points. Because in most cases the label is to be positioned in the direction of
405the center of a curve and the point at hand, it makes sense to take circles as
406the starting points for positioning the labels.
407
408To help us in positioning, we define a special square path, \type {freesquare}.
409This path is constructed out of 8~points that match the positions that are used
410to align labels.
411
412\startbuffer[d]
413path freesquare ;
414
415freesquare := ((-1,0)--(-1,-1)--(0,-1)--(+1,-1)--
416               (+1,0)--(+1,+1)--(0,+1)--(-1,+1)--cycle) scaled .5 ;
417\stopbuffer
418
419\typebuffer[d]
420
421We now show this free path together with a circle, using the following
422definitions:
423
424\startbuffer[e]
425drawpath        fullcircle scaled 3cm ;
426drawpoints      fullcircle scaled 3cm ;
427drawpointlabels fullcircle scaled 3cm ;
428currentpicture := currentpicture shifted (5cm,0) ;
429drawpath        freesquare scaled 3cm ;
430drawpoints      freesquare scaled 3cm ;
431drawpointlabels freesquare scaled 3cm ;
432\stopbuffer
433
434\typebuffer[e]
435
436We use two drawing macros that are part of the suite of visual debugging macros.
437
438\startlinecorrection[blank]
439\processMPbuffer[x,d,e]
440\stoplinecorrection
441
442As you can see, point~1 is the corner point that suits best for alignment when a
443label is put at point~1 of the circle. We will now rewrite \type {thefreelabel}
444in such a way that the appropriate point of the associated \type {freesquare} is
445found.
446
447\startbuffer[a]
448vardef thefreelabel (expr str, loc, ori) =
449  save s, p, q, l ; picture s ; path p, q ; pair l ;
450  s := thelabel(str,loc) ;
451  p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
452  q := freesquare xyscaled (urcorner s - llcorner s) ;
453  l := point (xpart (p intersectiontimes (ori--loc))) of q ;
454  draw q shifted loc withpen pencircle scaled .5pt ;
455  draw l shifted loc withcolor .625yellow ;
456  draw loc withcolor .625red ;
457  s
458enddef ;
459\stopbuffer
460
461\typebuffer[a]
462
463The macro xyscaled is part of \METAFUN\ and scales in two directions at once. The
464\METAPOST\ primitive \type {intersectiontimes} returns a pair of time values of
465the point where two paths intersect. The first part of the pair concerns the
466first path.
467
468\startlinecorrection[blank]
469\processMPbuffer[x,a,b,c]
470\stoplinecorrection
471
472We are now a small step from the exact placement. If we change the last line of
473the macro into:
474
475\starttyping
476(s shifted -l)
477\stoptyping
478
479we get the displacement we want. Although the final look and feel is also
480determined by the text itself, the average result is quite acceptable.
481
482\startbuffer[a]
483vardef thefreelabel (expr str, loc, ori) =
484  save s, p, q, l ; picture s ; path p, q ; pair l ;
485  s := thelabel(str,loc) ;
486  p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
487  q := freesquare xyscaled (urcorner s - llcorner s) ;
488  l := point (xpart (p intersectiontimes (ori--loc))) of q ;
489  draw q shifted loc withpen pencircle scaled .5pt ;
490  draw l shifted loc withcolor .625yellow ;
491  draw loc withcolor .625red ;
492  (s shifted -l)
493enddef ;
494\stopbuffer
495
496\startlinecorrection[blank]
497\processMPbuffer[x,a,b,c]
498\stoplinecorrection
499
500Because we also want to pass pictures, and add a bit of offset too, the final
501implementation is slightly more complicated. The picture is handled with an
502additional condition, and the offset with the \METAFUN\ macro \type {enlarged}.
503
504\startbuffer[a]
505newinternal freelabeloffset ; freelabeloffset := 3pt ;
506
507vardef thefreelabel (expr str, loc, ori) =
508  save s, p, q, l ; picture s ; path p, q ; pair l ;
509  interim labeloffset := freelabeloffset ;
510  s := if string str : thelabel(str,loc)
511       else          : str shifted -center str shifted loc fi ;
512  setbounds s to boundingbox s enlarged freelabeloffset ;
513  p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
514  q := freesquare xyscaled (urcorner s - llcorner s) ;
515  l := point (xpart (p intersectiontimes (ori--loc))) of q ;
516  setbounds s to boundingbox s enlarged -freelabeloffset ;
517  (s shifted -l)
518enddef ;
519\stopbuffer
520
521\typebuffer[a]
522
523Watch how we temporarily enlarge the bounding box of the typeset label text. We
524will now test this macro on a slightly rotated circle, using labels typeset by
525\TEX. The \type {reverse} is there purely for cosmetic reasons, to suit the label
526texts.
527
528\startbuffer[b]
529pickup pencircle scaled 1mm ;
530path p ; p := reverse fullcircle rotated -25 scaled 3cm ;
531draw p withcolor .625yellow ; pair cp ; cp := center p ;
532freedotlabel (btex \strut We can    etex, point 0 of p, cp) ;
533freedotlabel (btex \strut go on     etex, point 1 of p, cp) ;
534freedotlabel (btex \strut and on    etex, point 2 of p, cp) ;
535freedotlabel (btex \strut in        etex, point 3 of p, cp) ;
536freedotlabel (btex \strut defining  etex, point 4 of p, cp) ;
537freedotlabel (btex \strut funny     etex, point 5 of p, cp) ;
538freedotlabel (btex \strut macros.   etex, point 6 of p, cp) ;
539freedotlabel (btex \strut Can't we? etex, point 7 of p, cp) ;
540\stopbuffer
541
542\startlinecorrection[blank]
543\processMPbuffer[a,b]
544\stoplinecorrection
545
546\typebuffer[b]
547
548Unfortunately we can run into problems due to rounding errors. Therefore we use a
549less readable but more safe expression for calculating the intersection points.
550Instead of using point \type {loc} as endpoint we use \type {loc} shifted over a
551very small distance into the direction \type {loc} from \type{ori}. In the
552assignment to~\type {l} we replace \type {loc} by:
553
554\starttyping
555 ( (1+eps) * arclength(ori--loc) * unitvector(loc-ori) )
556\stoptyping
557
558\stopsection
559
560\startsection[title={Marking angles}]
561
562\index{angles}
563
564A convenient \METAPOST\ macro is \type {unitvector}. When we draw a line segment
565from the origin to the point returned by this macro, the segment has a length of
5661~base point. This macro has a wide range of applications, but some basic
567knowledge of vector algebra is handy. The following lines of \METAPOST\ code
568demonstrate the basics behind unitvectors.
569
570\startbuffer
571pair uv ; pickup pencircle scaled 1mm ; autoarrows := true ;
572draw fullcircle scaled 2cm withcolor .625red    ;
573for i=(10,35), (-40,-20), (85,-15) :
574  draw origin--i dashed evenly withcolor .625white ;
575  drawarrow origin--unitvector(i) scaled 1cm withcolor .625yellow ;
576endfor ;
577draw origin withcolor .625red ;
578\stopbuffer
579
580\typebuffer
581
582The circle has a radius of 1cm, and the three line segments are drawn from the
583origin in the direction of the points that are passed as arguments. Because the
584vector has length of~1, we scale it to the radius to let it touch the circle. By
585setting \type {autoarrows} we make sure that the arrowheads are scaled
586proportionally to the linewidth of 1~mm.
587
588\startlinecorrection[blank]
589\processMPbuffer
590\stoplinecorrection
591
592An application of this macro is drawing the angle between two lines. In the
593\METAPOST\ manual you can find two macros for drawing angles: \type {mark_angle}
594and \type {mark_rt_angle}. You may want to take a look at their definitions
595before we start developing our own alternatives.
596
597\startbuffer[x]
598pickup pencircle scaled 1mm ; autoarrows := true ;
599drawoptions(withcolor .625white) ;
600\stopbuffer
601
602\startbuffer[a]
603def anglebetween (expr a, b) =
604  (unitvector(a){a rotated 90} .. unitvector(b))
605enddef ;
606\stopbuffer
607
608\startbuffer[b]
609pair a, b ; a := (2cm,-1cm) ; b := (3cm,1cm) ;
610drawarrow origin--a ; drawarrow origin--b ;
611drawarrow anglebetween(a,b) scaled 1cm withcolor .625red ;
612\stopbuffer
613
614\startlinecorrection[blank]
615\processMPbuffer[x,a,b]
616\stoplinecorrection
617
618The previous graphic demonstrates what we want to accomplish: a circular curve
619indicating the angle between two straight lines. The lines and curve are drawn
620with the code:
621
622\typebuffer[b]
623
624where \type {anglebetween} is defined as:
625
626\typebuffer[a]
627
628Both unitvectors return just a point on the line positioned 1~unit (later scaled
629to 1cm) from the origin. We connect these points by a curve that starts in the
630direction at the first point. If we omit the \type {a rotated 90} direction
631specifier, we get:
632
633\startbuffer[a]
634def anglebetween (expr a, b) =
635  (unitvector(a) .. unitvector(b))
636enddef ;
637\stopbuffer
638
639\startlinecorrection[blank]
640\processMPbuffer[x,a,b]
641\stoplinecorrection
642
643These definitions of \type {anglebetween} are far from perfect. If we don't start
644in the origin, we get the curve in the wrong place and when we swap both points,
645we get the wrong curve.
646
647\startbuffer[a]
648def anglebetween (expr endofa, endofb, common, length) =
649  (unitvector (endofa-common){(endofa-common) rotated 90} ..
650   unitvector (endofb-common)) scaled length shifted common
651enddef ;
652\stopbuffer
653
654\startbuffer[b]
655pair a, b, c ; a := (2cm,-1cm) ; b := (3cm,1cm) ; c := (-1cm,.5cm) ;
656drawarrow c--a ; drawarrow c--b ;
657drawarrow anglebetween(a,b,c,1cm) withcolor .625red ;
658\stopbuffer
659
660The solution for the displacement is given in the \METAPOST\ manual and looks
661like this (we package the macro a bit different):
662
663\typebuffer[a]
664
665As you can see, we compensate for the origin of both vectors. This macro is
666called with a few more parameters. We need to pass the length, since we want to
667add the shift to the macro and the shift takes place after the scaling.
668
669\typebuffer[b]
670
671That the results are indeed correct, is demonstrated by the output of following
672example:
673
674\startlinecorrection[blank]
675\processMPbuffer[x,a,b]
676\stoplinecorrection
677
678However, when we swap the points, we get:
679
680\startbuffer[a]
681def anglebetween (expr endofb, endofa, common, length) =
682  (unitvector (endofa-common){(endofa-common) rotated 90} ..
683   unitvector (endofb-common)) scaled length shifted common
684enddef ;
685\stopbuffer
686
687\startlinecorrection[blank]
688\processMPbuffer[x,a,b]
689\stoplinecorrection
690
691This means that instead of rotating over $90$ degrees, we have to rotate over
692$-90$ or $270$ degrees. That way the arrow will also point in the other
693direction. There are undoubtedly more ways to determine the direction, but the
694following method also demonstrates the use of \type {turningnumber}, which
695reports the direction of a path. For this purpose we compose a dummy cyclic path.
696
697\startbuffer[a]
698vardef anglebetween (expr endofa, endofb, common, length) =
699  save tn ; tn := turningnumber(common--endofa--endofb--cycle) ;
700show tn ;
701  (unitvector(endofa-common){(endofa-common) rotated (tn*90)} ..
702   unitvector(endofb-common)) scaled length shifted common
703enddef ;
704\stopbuffer
705
706\typebuffer[a]
707
708Because we use an intermediate variable, just to keep things readable, we have to
709use \type {vardef} to hide the assignment for the outside world. We demonstrate
710this macro using the following code:
711
712\startbuffer[b]
713pair a, b, c ; a := (2cm,-1cm) ; b := (3cm,1cm) ; c := (-1cm,.5cm) ;
714drawarrow c--a ; drawarrow c--b ;
715drawarrow anglebetween(a,b,c,0.75cm) withcolor .625red ;
716drawarrow anglebetween(b,a,c,1.50cm) withcolor .625red ;
717\stopbuffer
718
719\typebuffer[b]
720
721Watch how both arrows point in the direction of the line that is determined by
722the second point.
723
724\startlinecorrection[blank]
725\processMPbuffer[x,a,b]
726\stoplinecorrection
727
728We now have the framework of an angle drawing macro ready and can start working
729placing the label.
730
731\startbuffer[a]
732vardef anglebetween (expr endofa, endofb, common, length, str) =
733  save curve, where ; path curve ; numeric where ;
734  where := turningnumber (common--endofa--endofb--cycle) ;
735  curve := (unitvector(endofa-common){(endofa-common) rotated (where*90)}
736         .. unitvector(endofb-common)) scaled length shifted common ;
737  draw thefreelabel(str,point .5 of curve,common) withcolor black ;
738  curve
739enddef ;
740\stopbuffer
741
742\typebuffer[a]
743
744The macro \type {thefreelabel} is part of \METAFUN\ and is explained in detail in
745\in {section} [sec:free labels]. This macro tries to place the label as good as
746possible without user interference.
747
748\startbuffer[b]
749pair a ; a := (2cm,-1cm) ; drawarrow origin--a ;
750pair b ; b := (3cm, 1cm) ; drawarrow origin--b ;
751drawarrow
752  anglebetween(a,b,origin,1cm,btex $\alpha$ etex)
753  withcolor .625red ;
754\stopbuffer
755
756\typebuffer[b]
757
758Instead of a picture we may also pass a string, but using \TEX\ by means of \type
759{btex}||\type {etex} often leads to better results.
760
761\startlinecorrection[blank]
762\processMPbuffer[x,a,b]
763\stoplinecorrection
764
765Because in most cases we want the length to be consistent between figures and
766because passing two paths is more convenient than passing three points, the final
767definition looks slightly different.
768
769\startbuffer[a]
770numeric anglelength ; anglelength := 20pt ;
771
772vardef anglebetween (expr a, b, str) = % path path string
773  save endofa, endofb, common, curve, where ;
774  pair endofa, endofb, common ; path curve ; numeric where ;
775  endofa := point length(a) of a ;
776  endofb := point length(b) of b ;
777  if round point 0 of a = round point 0 of b :
778    common := point 0 of a ;
779  else :
780    common := a intersectionpoint b ;
781  fi ;
782  where := turningnumber (common--endofa--endofb--cycle) ;
783  curve := (unitvector (endofa-common){(endofa-common) rotated (where*90)} ..
784            unitvector (endofb-common)) scaled anglelength shifted common ;
785  draw thefreelabel(str,point .5 of curve,common) withcolor black ;
786  curve
787enddef ;
788\stopbuffer
789
790\typebuffer[a]
791
792This macro has a few more \type {if}'s than its predecessor. First we test if the
793label is a string, and if so, we calculate the picture ourselves, otherwise we
794leave this to the user.
795
796\startbuffer[b]
797path a, b, c, d, e, f ;
798a := origin--( 2cm, 1cm) ; b := origin--( 1cm, 2cm) ;
799c := origin--(-2cm, 2cm) ; d := origin--(-2cm,-1cm) ;
800e := origin--(-1cm,-2cm) ; f := origin--( 1cm,-2cm) ;
801for i=a, b, c, d, e, f : drawarrow i ; endfor ;
802anglelength := 1.0cm ; drawoptions(withcolor .625red) ;
803drawarrow         anglebetween(a,b,btex $\alpha  $ etex) ;
804drawarrow         anglebetween(c,d,btex $\gamma  $ etex) ;
805drawarrow         anglebetween(e,f,btex $\epsilon$ etex) ;
806anglelength := 1.5cm ; drawoptions(withcolor .625yellow) ;
807drawdblarrow      anglebetween(b,c,btex $\beta   $ etex) ;
808drawarrow reverse anglebetween(d,e,btex $\delta  $ etex) ;
809drawarrow         anglebetween(a,f,btex $\zeta   $ etex) ;
810\stopbuffer
811
812\typebuffer[b]
813
814Because \type {anglebetween} returns a path, you can apply transformations to it,
815like reversing. Close reading of the previous code learns that the macro handles
816both directions.
817
818\startlinecorrection[blank]
819\processMPbuffer[x,a,b]
820\stoplinecorrection
821
822Multiples of 90 degrees are often identified by a rectangular symbol. We will now
823extend the previously defined macro in such a way that more types can be drawn.
824
825\startbuffer[a]
826numeric anglelength ; anglelength := 20pt ;
827numeric anglemethod ; anglemethod :=    1 ;
828
829vardef anglebetween (expr a, b, str) = % path path string
830  save pointa, pointb, common, middle, offset ;
831  pair pointa, pointb, common, middle, offset ;
832  save curve ; path curve ;
833  save where ; numeric where ;
834  if round point 0 of a = round point 0 of b :
835    common := point 0 of a ;
836  else :
837    common := a intersectionpoint b ;
838  fi ;
839  pointa := point anglelength on a ;
840  pointb := point anglelength on b ;
841  where  := turningnumber (common--pointa--pointb--cycle) ;
842  middle := ((common--pointa) rotatedaround (pointa,-where*90))
843                            intersectionpoint
844            ((common--pointb) rotatedaround (pointb, where*90)) ;
845  if     anglemethod = 1 :
846    curve  := pointa{unitvector(middle-pointa)}.. pointb;
847    middle := point .5 along curve ;
848  elseif anglemethod = 2 :
849    middle := common rotatedaround(.5[pointa,pointb],180) ;
850    curve  := pointa--middle--pointb ;
851  elseif anglemethod = 3 :
852    curve  := pointa--middle--pointb ;
853  elseif anglemethod = 4 :
854    curve  := pointa..controls middle..pointb ;
855    middle := point .5 along curve ;
856  fi ;
857  draw thefreelabel(str, middle, common) withcolor black ;
858  curve
859enddef ;
860\stopbuffer
861
862\typebuffer[a]
863
864\startbuffer[p]
865anglemethod := 1 ;
866\stopbuffer
867
868\startbuffer[q]
869anglemethod := 2 ;
870\stopbuffer
871
872\startbuffer[r]
873anglemethod := 3 ;
874\stopbuffer
875
876\startbuffer
877\startcombination[3*1]
878  {\processMPbuffer[x,a,p,b]} {method 1}
879  {\processMPbuffer[x,a,q,b]} {method 2}
880  {\processMPbuffer[x,a,r,b]} {method 3}
881\stopcombination
882\stopbuffer
883
884\placefigure
885  [here][fig:three methods]
886  {Three ways of marking angles.}
887  {\getbuffer}
888
889\in {Figure} [fig:three methods] shows the first three alternative methods
890implemented here. Instead of using \typ {unitvectors}, we now calculate the
891points using the \typ {arctime} and \typ {arclength} primitives. Instead of
892complicated expressions, we use the \METAFUN\ operators \type {along} and \type
893{on}. The following expressions are equivalent.
894
895\starttyping
896pointa := point anglelength on a ;
897middle := point .5 along curve ;
898
899pointa := point (arctime anglelength of a) of a ;
900middle := arctime (.5(arclength curve)) of curve) of curve ;
901\stoptyping
902
903The third method can be implemented in different, more math intensive ways, but
904the current implementation suits rather well and is understood by the author.
905
906\stopsection
907
908\startsection[reference=sec:color circles,title={Color circles}]
909
910\index{color}
911
912In \in {chapter} [sec:embedding] we showed a few color circles. Drawing such a
913graphic can be done in several ways, and here we will show a few methods. First
914we will demonstrate how you can apply \type {cutafter} and \type {cutbefore},
915next we will show how the \METAPOST\ macro \type {buildpath} can be used, and
916finally we will present a clean solution using \type {subpath}. We will assume
917that the circle is called with the macro:
918
919\starttyping
920colorcircle (4cm, red, green, blue) ;
921\stoptyping
922
923\startbuffer[circle]
924vardef colorcircle (expr size, red, green, blue) =
925  save r, g, b, rr, gg, bb, cc, mm, yy ;
926  save b_r, b_g, g_r, g_b ;
927  save radius ;
928
929  path r, g, b, rr, bb, gg, cc, mm, yy ;
930  pair b_r, b_g, g_r, g_b ;
931
932  numeric radius ; radius := 3cm ;
933
934  pickup pencircle scaled (radius/20) ;
935
936  r := g := b := fullcircle scaled radius shifted (0,radius/4);
937
938  r := r rotatedaround(origin, 15) ; % drawarrow r withcolor red   ;
939  g := g rotatedaround(origin,135) ; % drawarrow g withcolor green ;
940  b := b rotatedaround(origin,255) ; % drawarrow b withcolor blue  ;
941
942  b_r :=         b intersectionpoint r ; % draw b_r ;
943  b_g :=         b intersectionpoint g ; % draw b_g ;
944  g_r := reverse g intersectionpoint r ; % draw g_r ;
945  g_b := reverse g intersectionpoint b ; % draw g_b ;
946
947  bb := b cutafter  b_r ; bb := bb cutbefore b_g ; % drawarrow bb ;
948  gg := g cutbefore b_g ; gg := gg cutafter  g_r ; % drawarrow gg ;
949  rr := r cutbefore g_r &        r cutafter  b_r ; % drawarrow rr ;
950
951  cc := b cutbefore b_r ; cc := cc cutafter  g_b ; % drawarrow br ;
952  yy := g cutbefore g_r ; yy := yy cutafter  g_b ; % drawarrow rg ;
953  mm := r cutbefore g_r &        r cutafter  b_r ; % drawarrow gb ;
954
955  bb := gg -- rr -- reverse bb -- cycle ;
956  gg := bb rotatedaround(origin,120) ;
957  rr := bb rotatedaround(origin,240) ;
958
959  cc := mm -- cc -- reverse yy -- cycle ;
960  yy := cc rotatedaround(origin,120) ;
961  mm := cc rotatedaround(origin,240) ;
962
963  fill fullcircle scaled radius withcolor white ;
964
965  fill rr withcolor red   ; fill cc withcolor white-red   ;
966  fill gg withcolor green ; fill mm withcolor white-green ;
967  fill bb withcolor blue  ; fill yy withcolor white-blue  ;
968
969  for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ;
970
971  currentpicture := currentpicture xsized size ;
972enddef ;
973\stopbuffer
974
975We need to calculate seven paths. The first implementation does all the handywork
976itself and thereby is rather long, complicated and unreadable. It does not really
977use the strength of \METAPOST\ yet.
978
979\typebuffer[circle]
980
981In determining the right intersection points, you need to know where the path
982starts and in what direction it moves. In case of doubt, drawing the path as an
983arrow helps. If you want to see the small paths used, you need to comment the
984lines with the \type {fill}'s and uncomment the lines with \type {draw}'s. Due to
985the symmetry and the fact that we keep the figure centered around the origin, we
986only need to calculate two paths since we can rotate them.
987
988There are for sure more (efficient) ways to draw such a figure, but this one
989demonstrates a few new tricks, like grouping. We use grouping here because we
990want to use \type {mm} to indicate the magenta path, and \type {mm} normally
991means millimeter. Within a group, you can save variables. These get their old
992values when the group is left.
993
994With \type {for} we process multiple paths after each other. In this case it
995hardly saves tokens, but it looks more clever.
996
997One of the more efficient methods is using the \type {buildcycle} macro. This
998macro takes two or more paths and calculates the combined path. Although this is
999a rather clever macro, you should be prepared to help it a bit when paths have
1000multiple intersection points. Again, we could follow a more secure mathematical
1001method, but the next one took only a few minutes of trial and error. To save some
1002memory, we redefine the \type {colors} graphic.
1003
1004\startbuffer[demo]
1005colorcircle(4cm, red, green, blue) ;
1006\stopbuffer
1007
1008When we call this macro as:
1009
1010\typebuffer[demo]
1011
1012we get:
1013
1014\startlinecorrection[blank]
1015\processMPbuffer[circle,demo]
1016\stoplinecorrection
1017
1018Of course this macro is only used for demonstration purposes and has no real use.
1019
1020\startbuffer[circle]
1021vardef colorcircle (expr size, red, green, blue) =
1022  save r, g, b, rr, gg, bb, cc, mm, yy ; save radius ;
1023  path r, g, b, rr, bb, gg, cc, mm, yy ; numeric radius ;
1024
1025  radius := 5cm ; pickup pencircle scaled (radius/25) ;
1026
1027  r := g := b := fullcircle scaled radius shifted (0,radius/4) ;
1028
1029  r := r rotatedaround (origin, 15) ;
1030  g := g rotatedaround (origin,135) ;
1031  b := b rotatedaround (origin,255) ;
1032
1033  r := r rotatedaround(center r,-90) ;
1034  g := g rotatedaround(center g, 90) ;
1035
1036  gg := buildcycle(buildcycle(reverse r,b),g) ;
1037  cc := buildcycle(buildcycle(b,reverse g),r) ;
1038
1039  rr := gg rotatedaround(origin,120) ;
1040  bb := gg rotatedaround(origin,240) ;
1041
1042  yy := cc rotatedaround(origin,120) ;
1043  mm := cc rotatedaround(origin,240) ;
1044
1045  fill fullcircle scaled radius withcolor white ;
1046
1047  fill rr withcolor red   ; fill cc withcolor white-red   ;
1048  fill gg withcolor green ; fill mm withcolor white-green ;
1049  fill bb withcolor blue  ; fill yy withcolor white-blue  ;
1050
1051  for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ;
1052
1053  currentpicture := currentpicture xsized size ;
1054enddef ;
1055\stopbuffer
1056
1057\typebuffer [circle]
1058
1059Since we don't want to duplicate a graphic, this time we show the dark
1060alternatives.
1061
1062\startbuffer[demo]
1063colorcircle(4cm, .5red, .5green, .5blue) ;
1064\stopbuffer
1065
1066\typebuffer[demo]
1067
1068This kind of unsafe path calculations are very sensitive to breaking. Changing
1069the \type {radius/4} into something else demonstrates this but we will not
1070challenge this macro that much. Therefore, the 50\% color circle shows up as:
1071
1072\startlinecorrection[blank]
1073\processMPbuffer[circle,demo]
1074\stoplinecorrection
1075
1076This command is part of \METAFUN\ and can be used to determine nice color
1077combinations by also looking at their complementary colors.
1078
1079\startbuffer[demo]
1080colorcircle (4cm, .7red, .5green, .3blue) ;
1081\stopbuffer
1082
1083\typebuffer[demo]
1084
1085\startlinecorrection[blank]
1086\processMPbuffer[circle,demo]
1087\stoplinecorrection
1088
1089The next circle that we draw shows the three main colors used in this document.
1090This circle is not that beautiful.
1091
1092\startbuffer[demo]
1093colorcircle(4cm,.625red,.625yellow,.625white) ;
1094\stopbuffer
1095
1096\typebuffer[demo]
1097
1098\startlinecorrection[blank]
1099\processMPbuffer[circle,demo]
1100\stoplinecorrection
1101
1102This definition can be cleaned up a bit by using \type {transform}, but the fuzzy
1103\type {buildcycle}'s remain.
1104
1105\startbuffer[circle]
1106vardef colorcircle (expr size, red, green, blue) =
1107  save r, g, b, rr, gg, bb, cc, mm, yy ; save radius ;
1108  path r, g, b, rr, bb, gg, cc, mm, yy ; numeric radius ;
1109
1110  radius := 5cm ; pickup pencircle scaled (radius/25) ;
1111
1112  transform t ; t := identity rotatedaround(origin,120) ;
1113
1114  r := fullcircle scaled radius
1115   shifted (0,radius/4) rotatedaround(origin,15) ;
1116
1117  g := r transformed t ; b := g transformed t ;
1118
1119  r := r rotatedaround(center r,-90) ;
1120  g := g rotatedaround(center g, 90) ;
1121
1122  gg := buildcycle(buildcycle(reverse r,b),g) ;
1123  cc := buildcycle(buildcycle(b,reverse g),r) ;
1124
1125  rr := gg transformed t ; bb := rr transformed t ;
1126  yy := cc transformed t ; mm := yy transformed t ;
1127
1128  fill fullcircle scaled radius withcolor white ;
1129
1130  fill rr withcolor red   ; fill cc withcolor white-red   ;
1131  fill gg withcolor green ; fill mm withcolor white-green ;
1132  fill bb withcolor blue  ; fill yy withcolor white-blue  ;
1133
1134  for i = rr,gg,bb,cc,mm,yy : draw i withcolor .5white ; endfor ;
1135
1136  currentpicture := currentpicture xsized size ;
1137enddef ;
1138\stopbuffer
1139
1140\typebuffer [circle]
1141
1142\startbuffer[demo]
1143colorcircle(4cm,(.4,.6,.8),(.8,.4,.6),(.6,.8,.4));
1144\stopbuffer
1145
1146\startlinecorrection[blank]
1147\processMPbuffer[circle,demo]
1148\stoplinecorrection
1149
1150This rather nice circle is defined as:
1151
1152\typebuffer[demo]
1153
1154The final implementation, which is part of \METAFUN, is slightly more efficient.
1155
1156\startbuffer[circle]
1157vardef colorcircle (expr size, red, green, blue) =
1158  save r, g, b, c, m, y, w ; save radius ;
1159  path r, g, b, c, m, y, w ; numeric radius ;
1160
1161  radius := 5cm ; pickup pencircle scaled (radius/25) ;
1162
1163  transform t ; t := identity rotatedaround(origin,120) ;
1164
1165  r := fullcircle rotated 90 scaled radius
1166         shifted (0,radius/4) rotatedaround(origin,135) ;
1167
1168  b := r transformed t ; g := b transformed t ;
1169
1170  c := buildcycle(subpath(1,7) of g, subpath(1,7) of b) ;
1171  y := c transformed t ; m := y transformed t ;
1172
1173  w := buildcycle(subpath(3,5) of r,
1174         subpath(3,5) of g, subpath(3,5) of b) ;
1175
1176  pushcurrentpicture ;
1177
1178  fill r withcolor red   ;
1179  fill g withcolor green ;
1180  fill b withcolor blue  ;
1181  fill c withcolor white-red   ;
1182  fill m withcolor white-green ;
1183  fill y withcolor white-blue  ;
1184  fill w withcolor white ;
1185
1186  for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ;
1187
1188  currentpicture := currentpicture xsized size ;
1189
1190  popcurrentpicture ;
1191enddef ;
1192\stopbuffer
1193
1194\typebuffer [circle]
1195
1196Here, we first fill the primary circles, next we fill the secondary ones. These
1197also cover the center, which is why finally we fill the center with white.
1198
1199\startbuffer[demo]
1200colorcircle(4cm,(.2,.5,.8),(.8,.2,.5),(.5,.8,.2));
1201\stopbuffer
1202
1203\startlinecorrection[blank]
1204\processMPbuffer[circle,demo]
1205\stoplinecorrection
1206
1207The circle uses the following colors:
1208
1209\typebuffer[demo]
1210
1211The next graphic demonstrates how the subpaths look that build the shapes.
1212
1213\startbuffer[circle]
1214vardef colorcircle (expr size, red, green, blue) =
1215  save r, g, b, c, m, y, w ; save radius ;
1216  path r, g, b, c, m, y, w ; numeric radius ;
1217
1218  radius := 5cm ; pickup pencircle scaled (radius/25) ;
1219
1220  transform t ; t := identity rotatedaround(origin,120) ;
1221
1222  r := fullcircle rotated 90 scaled radius
1223         shifted (0,radius/4) rotatedaround(origin,135) ;
1224
1225  b := r transformed t ; g := b transformed t ;
1226
1227  c := buildcycle(subpath(1,7) of g,subpath(1,7) of b) ;
1228  y := c transformed t ; m := y transformed t ;
1229
1230  w := buildcycle(subpath(3,5) of r,
1231         subpath(3,5) of g, subpath(3,5) of b) ;
1232
1233  pushcurrentpicture ;
1234
1235  def do_it =
1236    fill r withcolor red   ;
1237    fill g withcolor green ;
1238    fill b withcolor blue  ;
1239    fill c withcolor white-red   ;
1240    fill m withcolor white-green ;
1241    fill y withcolor white-blue  ;
1242    fill w withcolor white ;
1243    for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ;
1244  enddef ;
1245
1246  autoarrows := true ;
1247
1248  do_it ;
1249  for i=r,g,b : drawarrow i withcolor black ; endfor ;
1250  currentpicture := currentpicture shifted (-2radius,0) ;
1251
1252  do_it ;
1253  for i=r,g,b : drawarrow subpath(1,7) of i withcolor black ; endfor ;
1254  currentpicture := currentpicture shifted (-2radius,0) ;
1255
1256  do_it ;
1257  for i=r,g,b : drawarrow subpath(3,5) of i withcolor black ; endfor ;
1258  currentpicture := currentpicture shifted (+4radius,2radius) ;
1259
1260  drawarrow r withpen pencircle scaled (radius/10) withcolor red   ;
1261  drawarrow g withpen pencircle scaled (radius/20) withcolor green ;
1262  drawarrow b withpen pencircle scaled (radius/40) withcolor blue  ;
1263  currentpicture := currentpicture shifted (-2radius,0) ;
1264
1265  drawarrow c withpen pencircle scaled (radius/10) withcolor white-red   ;
1266  drawarrow m withpen pencircle scaled (radius/20) withcolor white-green ;
1267  drawarrow y withpen pencircle scaled (radius/40) withcolor white-blue  ;
1268  currentpicture := currentpicture shifted (-2radius,0) ;
1269
1270  drawarrow w withcolor black ;
1271
1272  currentpicture := currentpicture xsized 3size ;
1273
1274  popcurrentpicture ;
1275enddef ;
1276\stopbuffer
1277
1278\startlinecorrection[blank]
1279\processMPbuffer[circle,demo]
1280\stoplinecorrection
1281
1282We did not mention what the push and pop commands are responsible for. Scaling
1283the current picture is well defined as long as we deal with one graphic. However,
1284if the current picture already has some content, this content is also scaled. The
1285push and pop commands let us add content to the current picture as well as
1286manipulating the picture as a whole without any side effects. The final result is
1287put on top of the already drawn content. Instead of the sequence:
1288
1289\starttyping
1290pushcurrentpicture ;
1291  ...
1292  currentpicture := currentpicture ... transformations ... ;
1293popcurrentpicture ;
1294\stoptyping
1295
1296you can say:
1297
1298\starttyping
1299pushcurrentpicture ;
1300  ...
1301popcurrentpicture ... transformations ... ;
1302\stoptyping
1303
1304Both are equivalent to:
1305
1306\starttyping
1307draw image ( ... ) ... transformations ... ;
1308\stoptyping
1309
1310For larger sequences of commands, the push||pop alternative gives a bit more more
1311readable code.
1312
1313\stopsection
1314
1315\startsection[title={Fool yourself}]
1316
1317When doing a literature search on the human perception of black||white edges, I
1318ran into several articles with graphics that I remember having seen before in
1319books on psychology, physiology and|/|or ergonomics. One of the articles was by
1320Edward H.~Adelson of MIT and we will use a few of his example graphics in our
1321exploration to what extend \METAPOST\ can be of help in those disciplines. Since
1322such graphics normally occur in typeset documents, we will define them in the
1323document source.
1324
1325\startbuffer[a]
1326\startbuffer
1327interim linecap := butt ; numeric u ; u := 1cm ;
1328pickup pencircle scaled .5u ;
1329for i=1u step u until 5u :
1330  draw (0,i) -- (5u,i) ;
1331endfor ;
1332for i=2u step u until 4u :
1333  draw   (u,i) -- (2u,i)                   withcolor .5white ;
1334  draw ((3u,i) -- (4u,i)) shifted (0,-.5u) withcolor .5white ;
1335endfor ;
1336\stopbuffer
1337\stopbuffer
1338
1339\startbuffer[b]
1340\placefigure
1341  [here][fig:tricked 1]
1342  {White's illusion.}
1343  {\processMPbuffer}
1344\stopbuffer
1345
1346\getbuffer[a,b]
1347
1348Unless you belong to the happy few whose visual capabilities are not distorted by
1349neural optimizations, in \in {figure} [fig:tricked 1] the gray rectangles at the
1350left look lighter than those on the right. Alas, you can fool yourself, but
1351\METAPOST\ does not cheat. This graphic, referred to as White's illusion, is
1352defined as follows.
1353
1354\typebuffer[a]
1355
1356Watch how we include the code directly. We have packaged this graphic in a buffer
1357which we include as a floating figure.
1358
1359\typebuffer[b]
1360
1361When passed to \METAPOST, this code is encapsulated in its \type {beginfig} and
1362\type {endfig} macros and thereby grouped. But any change to a variable that is
1363not explicitly saved, migrates to the outer level. In order to prevent all
1364successive graphics to have butt'd linecaps, we have to change this line
1365characteristic locally. Because \type {linecap} is defined as an internal
1366variable, we have to use \type {interim} to overload its value. Because \type {u}
1367is a rather commonly used scratch variable, we don't save its value.
1368
1369Watch how we use \type {u} as the loop step. In spite of what your eyes tell you,
1370this graphic only has two explicit color directives, both being 50\% black. In
1371the next example we will use some real colors.
1372
1373\startbuffer[a]
1374\startuseMPgraphic{first}
1375  numeric size, delta ;
1376  size := 2.5cm ; delta := size/3 ;
1377  color mainshade, topshade, bottomshade, centershade ;
1378  mainshade := \MPcolor{funcolor} ;
1379  topshade := .9mainshade ; bottomshade := .5mainshade ;
1380  centershade := .5[topshade,bottomshade] ;
1381\stopuseMPgraphic
1382\stopbuffer
1383
1384\startbuffer[b]
1385\startuseMPgraphic{second}
1386  \includeMPgraphic{first}
1387  fill fullsquare scaled size  withcolor topshade ;
1388  fill fullsquare scaled delta withcolor centershade ;
1389\stopuseMPgraphic
1390\stopbuffer
1391
1392\startbuffer[c]
1393\startuseMPgraphic{third}
1394  \includeMPgraphic{first}
1395  fill fullsquare scaled size  withcolor bottomshade ;
1396  fill fullsquare scaled delta withcolor centershade ;
1397\stopuseMPgraphic
1398\stopbuffer
1399
1400\getbuffer[a,b,c]
1401
1402\startbuffer[d]
1403\startcombination[5*2]
1404  {\definecolor[funcolor][red]   \useMPgraphic{second}} {}
1405  {\definecolor[funcolor][green] \useMPgraphic{second}} {}
1406  {\definecolor[funcolor][blue]  \useMPgraphic{second}} {}
1407  {\definecolor[funcolor][yellow]\useMPgraphic{second}} {}
1408  {\definecolor[funcolor][white] \useMPgraphic{second}} {}
1409  {\definecolor[funcolor][red]   \useMPgraphic{third}}  {}
1410  {\definecolor[funcolor][green] \useMPgraphic{third}}  {}
1411  {\definecolor[funcolor][blue]  \useMPgraphic{third}}  {}
1412  {\definecolor[funcolor][yellow]\useMPgraphic{third}}  {}
1413  {\definecolor[funcolor][white] \useMPgraphic{third}}  {}
1414\stopcombination
1415\stopbuffer
1416
1417\placefigure
1418  [here][fig:tricked 2]
1419  {The simultaneous contrast effect.}
1420  {\getbuffer[d]}
1421
1422In \in {figure} [fig:tricked 2] the small squares in the center of each colored
1423pair of big squares have the same shade, but the way we perceive them are
1424influenced by their surroundings. Both sets of squares are defined using usable
1425graphics. The top squares are defined as:
1426
1427\typebuffer[b]
1428
1429and the bottom squares are coded as:
1430
1431\typebuffer[c]
1432
1433Because both graphics share code, we have defined that code as a separate
1434graphic, that we include. The only point of interest in this definition is the
1435fact that we let \METAPOST\ interpolate between the two colors using \type {.5[
1436]}.
1437
1438\typebuffer[a]
1439
1440The color \type {funcolor} is provided by \CONTEXT, and since we want to use this
1441graphic with different colors, this kind of mapping is quite convenient. The
1442bunch of graphics is packaged in a combination with empty captions. Note how we
1443set the color before we include the graphic.
1444
1445\typebuffer[d]
1446
1447We use a similar arrangement for the following graphic, where we have replaced
1448the definitions of \type {first}, \type {second} and \type {third} by new
1449definitions.
1450
1451\startbuffer[a]
1452\startuseMPgraphic{first}
1453  numeric height, width, radius, gap ; gap := 1mm ;
1454  height = 2.5cm ; width := height/2 ; radius := height/2.5 ;
1455  color mainshade, leftshade, rightshade, centershade ;
1456  mainshade := \MPcolor{funcolor} ;
1457  leftshade := .9mainshade ; rightshade := .5mainshade ;
1458  centershade := .5[leftshade,rightshade] ;
1459  fill unitsquare xyscaled ( width,height) withcolor leftshade ;
1460  fill unitsquare xyscaled (-width,height) withcolor rightshade ;
1461  draw (fullcircle scaled radius) shifted (0,height/2)
1462    withpen pencircle scaled (radius/2) withcolor centershade ;
1463\stopuseMPgraphic
1464\stopbuffer
1465
1466\startbuffer[b]
1467\startuseMPgraphic{second}
1468  \includeMPgraphic{first}
1469  interim linecap := butt ; pickup pencircle scaled gap ;
1470  draw (0,0) -- (0,height) withcolor white ;
1471\stopuseMPgraphic
1472\stopbuffer
1473
1474\startbuffer[c]
1475\startuseMPgraphic{third}
1476  \includeMPgraphic{first}
1477  picture p, q ; p := q := currentpicture ;
1478  clip p to unitsquare xscaled  width yscaled height ;
1479  clip q to unitsquare xscaled -width yscaled height ;
1480  currentpicture := p ;
1481  addto currentpicture also q shifted (0,radius/2) ;
1482\stopuseMPgraphic
1483\stopbuffer
1484
1485\getbuffer[a,b,c]
1486
1487\startbuffer[d]
1488\startcombination[5*3]
1489  {\definecolor[funcolor][red]   \useMPgraphic{first}}  {}
1490  {\definecolor[funcolor][green] \useMPgraphic{first}}  {}
1491  {\definecolor[funcolor][blue]  \useMPgraphic{first}}  {}
1492  {\definecolor[funcolor][yellow]\useMPgraphic{first}}  {}
1493  {\definecolor[funcolor][white] \useMPgraphic{first}}  {}
1494  {\definecolor[funcolor][red]   \useMPgraphic{second}} {}
1495  {\definecolor[funcolor][green] \useMPgraphic{second}} {}
1496  {\definecolor[funcolor][blue]  \useMPgraphic{second}} {}
1497  {\definecolor[funcolor][yellow]\useMPgraphic{second}} {}
1498  {\definecolor[funcolor][white] \useMPgraphic{second}} {}
1499  {\definecolor[funcolor][red]   \useMPgraphic{third}}  {}
1500  {\definecolor[funcolor][green] \useMPgraphic{third}}  {}
1501  {\definecolor[funcolor][blue]  \useMPgraphic{third}}  {}
1502  {\definecolor[funcolor][yellow]\useMPgraphic{third}}  {}
1503  {\definecolor[funcolor][white] \useMPgraphic{third}}  {}
1504\stopcombination
1505\stopbuffer
1506
1507\placefigure
1508  [here][fig:tricked 3]
1509  {Koffka's examples of manipulating contrast by changing
1510   the spatial configuration.}
1511  {\getbuffer[d]}
1512
1513The definition of the first row of \in {figure} [fig:tricked 3] is used in the
1514second and third and therefore is the most complicated. We use quite some scratch
1515variables to reach a high level of abstraction. The \type {xyscaled} operator is
1516a \METAFUN\ macro.
1517
1518\typebuffer[a]
1519
1520The graphics of the second row extends those of the first by drawing a white line
1521through the middle. In this example setting the linecap is not really needed,
1522because rounded top and bottoms in white are invisible and the part that extends
1523beyond the points does not count in calculating the bounding box.
1524
1525\typebuffer[b]
1526
1527The third row graphics again extend the first graphic. First we copy the picture
1528constructed so far. Watch the double assignment. Next we clip the pictures in
1529half, and shift the right half down over the width of the circle.
1530
1531\typebuffer[c]
1532
1533\stopsection
1534
1535% \startsection[title={Puzzles}]
1536%
1537% {\em Maybe.}
1538%
1539% \stopsection
1540%
1541% \startsection[title={Flow charts}]
1542%
1543% {\em Instead of starting anew every time, you can use predefined macros, like
1544% those in the flow chart module. Let's see how we can influence the \METAPOST\
1545% code. Maybe not here.}
1546%
1547% \stopsection
1548%
1549% \startsection[title={Chemistry}]
1550%
1551% {\em \METAPOST\ can do it's work unseen, as in the chemistry module that comes
1552% with \CONTEXT. There, \METAPOST\ is used as one of the graphical plug||ins. It
1553% demonstrates that we can put \METAPOST\ to work without seeing any code.}
1554%
1555% \stopsection
1556
1557\startsection[title={Growing graphics}]
1558
1559Although \METAPOST\ is not really suited as a simulation engine, it is possible
1560to build graphics that are built and displayed incrementally with a sequence of
1561mouse clicks. The following example is the result of an email discussion David
1562Arnold and the author had while \METAFUN\ evolved.
1563
1564Instead of defining the graphics in a separate \METAPOST\ file, we will
1565incorporate them in the document source in which they are used. We can use
1566several methods.
1567
1568\startitemize[n]
1569\startitem
1570    Define macros and figures in a separate file and include the graphics as
1571    external graphics.
1572\stopitem
1573\startitem
1574    Define everything in the document source as usable graphics and include the
1575    graphics using \type {\useMPgraphic}.
1576\stopitem
1577\startitem
1578    Package the graphic components in buffers and paste those together as
1579    graphics that can be processed at run time.
1580\stopitem
1581\stopitemize
1582
1583The first method is the most independent one, which has its advantages if we want
1584to use the graphics in other applications too. The second method works well in
1585graphics where parts of the definitions change between invocations of the
1586graphic. This method follows the template:
1587
1588\starttyping
1589\startuseMPgraphic{whatever}
1590 ...
1591\stopuseMPgraphic
1592
1593\startuseMPgraphic{result}
1594  ...
1595  \includeMPgraphic{whatever}
1596  ...
1597\stopuseMPgraphic
1598
1599\useMPgraphic{result}
1600\stoptyping
1601
1602The disadvantage of this method is that it cannot be combined with \type
1603{btex}||\type {etex} since it is nearly impossible to determine when, how, and to
1604what extent the content of a graphic should be expanded before writing it to the
1605temporary \METAPOST\ file.
1606
1607Therefore, we will demonstrate how buffers can be used. This third method closely
1608parallels the first way of defining graphics. A nice side effect is that we can
1609easily typeset these buffers verbatim, which we did to typeset this document.
1610
1611We are going to do a classic compass and straightedge construction, the bisection
1612of a line segment joining two arbitrary points. We will construct five graphics,
1613where each one displays one step of the construction. We will embed each graphic
1614in a start||stop command. Later we will see the advantage of this strategy.
1615
1616\startbuffer
1617\startbuffer[a]
1618def start_everything = enddef ;
1619def stop_everything  = enddef ;
1620\stopbuffer
1621\stopbuffer
1622
1623\typebuffer \getbuffer
1624
1625\startbuffer
1626\startbuffer[b]
1627numeric u, w ; u := .5cm ; w := 1pt ;
1628
1629pickup pencircle scaled w ;
1630
1631def draw_dot expr p =
1632  draw p withpen pencircle scaled 3w ;
1633enddef ;
1634
1635def stand_out =
1636  drawoptions(withcolor .625red) ;
1637enddef ;
1638\stopbuffer
1639\stopbuffer
1640
1641We are going to draw a few dots, and to force consistency we first define a macro
1642\type {draw_dot}. The current step will be highlighted in red using \type
1643{stand_out}.
1644
1645\typebuffer \getbuffer
1646
1647\startbuffer
1648\startbuffer[c]
1649def draw_basics =
1650  pair pointA, pointB ; path lineAB ;
1651  pointA := origin ; pointB := pointA shifted (5u,0) ;
1652  lineAB := pointA -- pointB ;
1653  draw lineAB ;
1654  draw_dot pointA ; label.lft(btex A etex, pointA) ;
1655  draw_dot pointB ; label.rt (btex B etex, pointB) ;
1656enddef ;
1657\stopbuffer
1658\stopbuffer
1659
1660First, we construct the macro that will plot two points $A$ and $B$ and connect
1661them with a line segment.
1662
1663\typebuffer \getbuffer
1664
1665\startbuffer
1666\startbuffer[1]
1667start_everything ;
1668  stand_out ; draw_basics ;
1669stop_everything ;
1670\stopbuffer
1671\stopbuffer
1672
1673The code in this buffer executes the preceding macros. The \type {..._everything}
1674commands are still undefined, but later we can use these hooks for special
1675purposes.
1676
1677\typebuffer \getbuffer
1678
1679This graphic can now be embedded by the \CONTEXT\ command
1680\type {\processMPbuffer}. This command, like the ordinary
1681buffer inclusion commands, accepts a list of buffers.
1682
1683\startbuffer
1684\startlinecorrection[blank]
1685\ruledhbox{\processMPbuffer[a,b,c,1]}
1686\stoplinecorrection
1687\stopbuffer
1688
1689\typebuffer
1690
1691We use \type {\ruledhbox} to show the tight bounding box of the graphic. The line
1692correction takes care of proper spacing around non textual content, like
1693graphics. \footnote {These spacing commands try to get the spacing around the
1694content visually compatible, and take the height and depth of the preceding and
1695following text into account.} This is only needed when the graphic is part of the
1696text flow!
1697
1698\getbuffer
1699
1700Next, we draw two circles of equal radius, one centered at point $A$, the other
1701at point $B$.
1702
1703\startbuffer
1704\startbuffer[d]
1705def draw_circles =
1706  path circleA, circleB ; numeric radius, distance ;
1707  distance := (xpart pointB) - (xpart pointA) ;
1708  radius := 2/3 * distance ;
1709  circleA := fullcircle scaled (2*radius) ;
1710  circleB := circleA shifted pointB ;
1711  draw circleA ;
1712  draw circleB ;
1713enddef ;
1714\stopbuffer
1715\stopbuffer
1716
1717\typebuffer \getbuffer
1718
1719\startbuffer
1720\startbuffer[2]
1721start_everything ;
1722  draw_basics ; stand_out ; draw_circles ;
1723stop_everything ;
1724\stopbuffer
1725\stopbuffer
1726
1727As you can see, we move down the \type {stand_out} macro so that only the
1728additions are colored red.
1729
1730\typebuffer \getbuffer
1731
1732We now use \type{\processMPbuffer[a,b,c,d,2]} to include the latest step.
1733
1734\startlinecorrection[blank]
1735\ruledhbox{\processMPbuffer[a,b,c,d,2]}
1736\stoplinecorrection
1737
1738The next step in the construction of the perpendicular bisector requires that we
1739find and label the points of intersection of the two circles centered at points
1740$A$ and $B$. The intersection points are calculated as follows. Watch the \type
1741{reverse} operation, which makes sure that we get the second intersection point.
1742
1743\startbuffer
1744\startbuffer[e]
1745def draw_intersection =
1746  pair pointC, pointD ;
1747  pointC := circleA intersectionpoint circleB ;
1748  pointD := (reverse circleA) intersectionpoint (reverse circleB) ;
1749  draw_dot pointC ; label.lft(btex C etex, pointC shifted (-2w,0)) ;
1750  draw_dot pointD ; label.lft(btex D etex, pointD shifted (-2w,0)) ;
1751enddef ;
1752\stopbuffer
1753\stopbuffer
1754
1755\typebuffer \getbuffer
1756
1757\startbuffer
1758\startbuffer[3]
1759start_everything ;
1760  draw_basics ; draw_circles ; stand_out ; draw_intersection ;
1761stop_everything ;
1762\stopbuffer
1763\stopbuffer
1764
1765In placing the label, we must make sure that the text runs free of the lines and
1766curves. Again, move the \type {stand_out} macro just prior to \type
1767{draw_intersection} macro, so that this step is highlighted in the drawing color,
1768while prior steps are drawn in the default color (in this case black).
1769
1770\typebuffer \getbuffer
1771
1772\startlinecorrection[blank]
1773\ruledhbox{\processMPbuffer[a,b,c,d,e,3]}
1774\stoplinecorrection
1775
1776The line drawn through points $C$ and $D$ will be the perpendicular bisector of
1777the line segment connecting points $A$ and $B$. In the next step we will draw a
1778line using the plain \METAPOST\ \type {drawdblarrow} macro that draws arrowheads
1779at each end of a path.
1780
1781\startbuffer
1782\startbuffer[f]
1783def draw_bisector =
1784  path lineCD ;
1785  lineCD := origin -- origin shifted (2*distance,0) ;
1786  lineCD := lineCD rotated 90 shifted 0.5[pointA,pointB] ;
1787  lineCD := lineCD shifted (0,-distance) ;
1788  drawdblarrow lineCD ;
1789enddef ;
1790\stopbuffer
1791
1792\startbuffer[4]
1793start_everything ;
1794  draw_basics ; draw_circles ; draw_intersection ; stand_out ;
1795  draw_bisector ;
1796stop_everything ;
1797\stopbuffer
1798\stopbuffer
1799
1800\typebuffer \getbuffer
1801
1802\startlinecorrection[blank]
1803\ruledhbox{\processMPbuffer[a,b,c,d,e,f,4]}
1804\stoplinecorrection
1805
1806The following code draws the intersection of line $C-D$ and line segment $A-B$,
1807which can be shown to be the midpoint of segment $A-B$.
1808
1809\startbuffer
1810\startbuffer[g]
1811def draw_midpoint =
1812  pair pointM ;
1813  pointM := lineCD intersectionpoint lineAB ;
1814  draw_dot pointM ; label.llft(btex M etex, pointM) ;
1815enddef ;
1816\stopbuffer
1817
1818\startbuffer[5]
1819start_everything ;
1820  draw_basics ; draw_circles ; draw_intersection ; draw_bisector ;
1821  stand_out ; draw_midpoint ;
1822stop_everything ;
1823\stopbuffer
1824\stopbuffer
1825
1826\typebuffer \getbuffer
1827
1828\startlinecorrection[blank]
1829\ruledhbox{\processMPbuffer[a,b,c,d,e,f,g,5]}
1830\stoplinecorrection
1831
1832As long as we place the graphics as individual insertions in our document,
1833everything is fine. However, if we wish to place them all at once, or as we shall
1834see later, place them on top of one another in a fieldstack, it makes sense to
1835give them all the same bounding box. We can do this by completing the \type
1836{start_everything} and \type {stop_everything} commands.
1837
1838\startbuffer
1839\startbuffer[a]
1840def start_everything =
1841  path bb ;
1842  draw_basics ;
1843  draw_circles ;
1844  draw_intersection ;
1845  draw_bisector ;
1846  draw_midpoint ;
1847  bb := boundingbox currentpicture ;
1848  currentpicture := nullpicture ;
1849enddef ;
1850
1851def stop_everything =
1852  setbounds currentpicture to bb ;
1853enddef ;
1854\stopbuffer
1855\stopbuffer
1856
1857\typebuffer \getbuffer
1858
1859In \in {figure} [fig:1 till 5] we demonstrate the effect of this redefinition.
1860For this purpose we scale down the graphic to a comfortable 40\%, of course by
1861using an additional buffer. We also visualize the bounding box.
1862
1863\startbuffer
1864\startbuffer[h]
1865def stop_everything =
1866  setbounds currentpicture to bb ;
1867  draw bb withpen pencircle scaled .5pt withcolor .625yellow ;
1868  currentpicture := currentpicture scaled .4 ;
1869enddef ;
1870\stopbuffer
1871\stopbuffer
1872
1873\typebuffer \getbuffer
1874
1875The graphic itself is defined as follows. Watch how we use the default buffer to
1876keep the definitions readable.
1877
1878\startbuffer
1879\startbuffer
1880\startcombination[5*1]
1881  {\processMPbuffer[a,b,c,h,d,e,f,g,1]} {step 1}
1882  {\processMPbuffer[a,b,c,h,d,e,f,g,2]} {step 2}
1883  {\processMPbuffer[a,b,c,h,d,e,f,g,3]} {step 3}
1884  {\processMPbuffer[a,b,c,h,d,e,f,g,4]} {step 4}
1885  {\processMPbuffer[a,b,c,h,d,e,f,g,5]} {step 5}
1886\stopcombination
1887\stopbuffer
1888
1889\placefigure
1890  [here][fig:1 till 5]
1891  {The five graphics, each with the same bounding box.}
1892  {\getbuffer}
1893\stopbuffer
1894
1895\typebuffer \getbuffer
1896
1897As the original purpose of these graphics was not to show them side by side, but
1898to present them as field stack in a document to be viewed at the computer screen.
1899For this purpose we have to define the graphics as symbols.
1900
1901\startbuffer
1902\definesymbol[step 1][{\processMPbuffer[a,b,c,d,e,f,g,1]}]
1903\definesymbol[step 2][{\processMPbuffer[a,b,c,d,e,f,g,2]}]
1904\definesymbol[step 3][{\processMPbuffer[a,b,c,d,e,f,g,3]}]
1905\definesymbol[step 4][{\processMPbuffer[a,b,c,d,e,f,g,4]}]
1906\definesymbol[step 5][{\processMPbuffer[a,b,c,d,e,f,g,5]}]
1907\stopbuffer
1908
1909\typebuffer \getbuffer
1910
1911A field stack is a sequence of overlayed graphics. We will arrange these to cycle
1912manually, with clicks of the mouse, through the sequence of graphs depicting the
1913construction of the midpoint of segment $A-B$. So, in fact we are dealing with a
1914manual simulation. The definition of such a stack is as follows:
1915
1916\startbuffer
1917\definefieldstack
1918  [midpoint construction]
1919  [step 1, step 2, step 3, step 4, step 5]
1920  [frame=on,offset=3pt,framecolor=darkyellow,rulethickness=1pt]
1921\stopbuffer
1922
1923\typebuffer \getbuffer
1924
1925The first argument is to be a unique identifier, the second argument takes a list
1926of symbols, while the third argument accepts settings. More on this command can
1927be found in the \CONTEXT\ manuals.
1928
1929The stack is shown as \in {figure} [fig:steps]. Its caption provides a button,
1930which enables the reader to cycle through the stack. We call this a stack because
1931the graphics are positioned on top of each other. Only one of them is visible at
1932any time.
1933
1934\startbuffer
1935\placefigure
1936  [here][fig:steps]
1937  {Bisecting a line segment with compass and straightedge? Just
1938   click \goto {here} [JS(Walk_Field{midpoint construction})] to
1939   walk through the construction! (This stack is only visible
1940   in a \PDF\ viewer that supports widgets.)}
1941  {\framed{\startoverlay
1942     {\symbol[step 1]}
1943     {\fieldstack[midpoint construction]}
1944   \stopoverlay}}
1945\stopbuffer
1946
1947\typebuffer
1948
1949We cheat a bit and overlay the stack over the first symbol because otherwise
1950nothing shows up in print (nowadays I mostly use sumatrapdf).
1951
1952{\setupinteraction[color=darkred,contrastcolor=darkred]\getbuffer}
1953
1954At the start of this section, we mentioned three methods. When we use the first
1955method of putting all the graphics in an external \METAPOST\ file, the following
1956framework suits. We assume that the file is called \type {step.mp} and that it is
1957kept by the user along with his document source. We start with the definitions of
1958the graphic steps. These are the same as the ones shown previously.
1959
1960\starttyping
1961def draw_basics       = ... enddef ;
1962def draw_circles      = ... enddef ;
1963def draw_intersection = ... enddef ;
1964def draw_bisector     = ... enddef ;
1965def draw_midpoint     = ... enddef ;
1966def stand_out         = ... enddef ;
1967\stoptyping
1968
1969We can safe some code by letting the \type {..._everything} take care of the
1970\type {beginfig} and \type {endfig} macros.
1971
1972\starttyping
1973def start_everything (expr n) = beginfig(n) ; ... enddef ;
1974def stop_everything           =    ... ; endfig ; enddef ;
1975\stoptyping
1976
1977The five graphics now become:
1978
1979\starttyping
1980start_everything (1) ;
1981  stand_out ; draw_basics ;
1982stop_everything ;
1983
1984start_everything (2) ;
1985  draw_basics ; stand_out ; draw_circles ;
1986stop_everything ;
1987
1988start_everything (3) ;
1989  draw_basics ; draw_circles ; stand_out ; draw_intersection ;
1990stop_everything ;
1991
1992start_everything (4) ;
1993  draw_basics ; draw_circles ; draw_intersection ; stand_out ;
1994  draw_bisector ;
1995stop_everything ;
1996
1997start_everything (5) ;
1998  draw_basics ; draw_circles ; draw_intersection ; draw_bisector ;
1999  stand_out ; draw_midpoint ;
2000stop_everything ;
2001\stoptyping
2002
2003The definitions of the symbols now refer to an external
2004figure.
2005
2006\starttyping
2007\definesymbol[step 1][{\externalfigure[step.1]}]
2008\definesymbol[step 2][{\externalfigure[step.2]}]
2009\definesymbol[step 3][{\externalfigure[step.3]}]
2010\definesymbol[step 4][{\externalfigure[step.4]}]
2011\definesymbol[step 5][{\externalfigure[step.5]}]
2012\stoptyping
2013
2014Which method is used, depends on the way the graphics are used. In this example
2015we wanted to change the definition of \type {..._everything}, so here the third
2016method was quite useful.
2017
2018\stopsection
2019
2020\startsection[title={Simple Logos}]
2021
2022\startbuffer[ns]
2023numeric width, height, line, delta ;
2024width = 5cm ; height = width/2 ; line = height/4 ; delta = line ;
2025
2026linejoin := mitered ; pickup pencircle scaled line ;
2027
2028color nsblue   ; nsblue   := (0,0,1) ;
2029color nsyellow ; nsyellow := (1,1,0) ;
2030
2031z1 = (0, height/2) ;
2032z2 = (width/2-height/4, y1) ;
2033z3 = (width/2+height/4, y4) ;
2034z4 = (width, 0) ;
2035
2036z5 = (x4+height/2, y1) ;
2037z6 = (x4, 2y1) ;
2038z7 = 1.5[z5,z6] ;
2039
2040path p ; p := z1--z2--z3--z4 ; path q ; q := z3--z4--z5--z7 ;
2041
2042numeric d, lx, ly, ux, uy ; d = line/2 ;
2043
2044lx = -3d - d/3  ; ly = -d ; ux = rt x5 + d/3 ; uy = top y6 ;
2045
2046path r ; r := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle;
2047
2048lx := lx-delta ; ly := ly-delta ; ux := ux+delta ; uy := uy+delta ;
2049
2050path s ; s := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle;
2051
2052draw p withcolor nsblue ; draw q withcolor nsblue ;
2053
2054addto currentpicture also currentpicture
2055  rotatedaround (.5[z2,z3],180) shifted (height/4,height/2) ;
2056
2057picture savedpicture ; savedpicture := currentpicture ;
2058
2059clip currentpicture to r ;
2060setbounds currentpicture to r ;
2061
2062savedpicture := currentpicture ; currentpicture := nullpicture ;
2063
2064fill s withcolor nsyellow ;
2065addto currentpicture also savedpicture ;
2066\stopbuffer
2067
2068Many company logos earn their beauty from their simplicity. One of the logos that
2069most Dutch people have imprinted in their mind is that of the Dutch Railway
2070Company (NS). An interesting feature of this logo is that, although it is widely
2071known, drawing it on a piece of paper from mind is a task that many people fail.
2072
2073\startlinecorrection[blank]
2074\processMPbuffer[ns]
2075\stoplinecorrection
2076
2077This logo makes a good candidate for demonstrating a few fine points of drawing
2078graphics, like using linear equations, setting line drawing characteristics,
2079clipping and manipulating bounding boxes.
2080
2081The implementation below is quite certainly not according to the official
2082specifications, but it can nevertheless serve as an example of defining such
2083logos.
2084
2085\startbuffer[a]
2086numeric width  ; width  = 3cm ;
2087numeric height ; height = width/2 ;
2088numeric line   ; line   = height/4 ;
2089\stopbuffer
2090
2091As always, we need to determine the dimensions first. Here, both the height and
2092line width depend on the width of the graphic.
2093
2094Instead of calculating the blue shape such that it will be a filled outline, we
2095will draw the logo shape using line segments. This is why we need the \type
2096{line} parameter.
2097
2098\typebuffer[a]
2099
2100We want sharp corners which can be achieved by setting \type {linejoin} to \type
2101{mitered}.
2102
2103\startbuffer[b]
2104linejoin := mitered ; pickup pencircle scaled line ;
2105\stopbuffer
2106
2107\typebuffer[b]
2108
2109The colors are rather primary blue and yellow. At the time of writing this
2110manual, Dutch trains are still painted yellow, so we will use that shade as
2111background color.
2112
2113\startbuffer[c]
2114color nsblue   ; nsblue   := (0,0,1) ;
2115color nsyellow ; nsyellow := (1,1,0) ;
2116\stopbuffer
2117
2118\typebuffer[c]
2119
2120We will now describe the main curves. Although these expressions are not that
2121advanced, they demonstrate that we can express relationships instead of using
2122assignments.
2123
2124\startbuffer[d]
2125z1 = (0, height/2) ;
2126z2 = (width/2-height/4, y1) ;
2127z3 = (width/2+height/4, y4) ;
2128z4 = (width, 0) ;
2129
2130path p ; p := z1--z2--z3--z4 ;
2131\stopbuffer
2132
2133\typebuffer[d]
2134
2135Although it is accepted to consider \type {z} to be a variable, it is in fact a
2136\type {vardef} macro, that expands into a pair \type {(x,y)}. This means that the
2137previous definitions internally become:
2138
2139\starttyping
2140(x1,y1) = (0, height/2) ;
2141(x2,y2) = (width/2-height/4, y1) ;
2142(x3,y3) = (width/2+height/4, y4) ;
2143(x4,y4) = (width, 0) ;
2144\stoptyping
2145
2146These 8 relations can be solved by \METAPOST, since all dependencies are known.
2147
2148\starttyping
2149x1 = 0                ; y1 = height/2 ;
2150x2 = width/2-height/4 ; y2 = y1       ;
2151x3 = width/2+height/4 ; y3 = y4       ;
2152x4 = width            ; y4 = 0        ;
2153\stoptyping
2154
2155Since we express the variables \type {x} and \type {y} in terms of relations, we
2156cannot reuse them, because that would mean that inconsistent relations occur. So,
2157the following lines will lead to an error message:
2158
2159\starttyping
2160z1 = (10,20) ; z1 = (30,50) ;
2161\stoptyping
2162
2163For similar reasons, we may not assign a value (using \type {:=}) to such a \type
2164{z} variable. Within a \METAPOST\ figure, \type {z} variables are automatically
2165saved, which means that they can be reused for each figure.
2166
2167\startbuffer[x]
2168drawpath p ; drawpoints p ; drawpointlabels p ;
2169\stopbuffer
2170
2171So far, we have defined the following segment of the logo.
2172
2173\startlinecorrection[blank]
2174\processMPbuffer[a,b,c,d,x]
2175\stoplinecorrection
2176
2177\startbuffer[e]
2178z5 = (x4+height/2, y1) ;
2179z6 = (x4, 2y1) ;
2180z7 = 1.5[z5,z6] ;
2181
2182path q ; q := z3--z4--z5--z7 ;
2183\stopbuffer
2184
2185The next expressions are used to define the second segment. The third expression
2186determines \type {z7} to be positioned on the line \type {z5--z6}, where we
2187extend this line by 50\%.
2188
2189\typebuffer[e]
2190
2191\startbuffer[x]
2192drawpath q ; drawpoints q ; drawpointlabels q ;
2193\stopbuffer
2194
2195\startlinecorrection[blank]
2196\processMPbuffer[a,b,c,d,e,x]
2197\stoplinecorrection
2198
2199If we combine these two segments, we get:
2200
2201\startbuffer[x]
2202drawpath p ; drawpoints p ; drawpointlabels p ;
2203swappointlabels := true ;
2204drawpath q ; drawpoints q ; drawpointlabels q ;
2205\stopbuffer
2206
2207\startlinecorrection[blank]
2208\processMPbuffer[a,b,c,d,e,x]
2209\stoplinecorrection
2210
2211However, when we draw them using the right linewidth and color, you will notice
2212that we're not yet done:
2213
2214\startbuffer[f]
2215draw p withcolor nsblue ; draw q withcolor nsblue ;
2216\stopbuffer
2217
2218\startlinecorrection[blank]
2219\processMPbuffer[a,b,c,d,e,f]
2220\stoplinecorrection
2221
2222The second curve is similar to the first one, but rotated over 180 degrees.
2223
2224\startbuffer[g]
2225addto currentpicture also currentpicture
2226  rotatedaround (.5[z2,z3],180) shifted (height/4,height/2) ;
2227\stopbuffer
2228
2229\typebuffer[g]
2230
2231\startlinecorrection[blank]
2232\processMPbuffer[a,b,c,d,e,f,g]
2233\stoplinecorrection
2234
2235In order to get the sharp edges, we need to clip off part of
2236the curves and at first sight, we may consider using a
2237scaled bounding box. However, when we show the natural
2238bounding box, you will notice that a more complicated bit of
2239calculations is needed.
2240
2241\startbuffer[x]
2242draw boundingbox currentpicture
2243  withpen pencircle scaled .5mm withcolor .625white ;
2244\stopbuffer
2245
2246\startlinecorrection[blank]
2247\processMPbuffer[a,b,c,d,e,f,g,x]
2248\stoplinecorrection
2249
2250The right clip path is calculated using the following expressions. Watch how we
2251use \type {rt} and \type {top} to correct for the linewidth.
2252
2253\startbuffer[h]
2254numeric d, lx, ly, ux, uy ; d = line/2 ;
2255
2256lx = -3d - d/3  ; ly = -d ; ux = rt x5 + d/3 ; uy = top y6 ;
2257
2258path r ; r := (lx,ly)--(ux,ly)--(ux,uy)--(lx,uy)--cycle;
2259\stopbuffer
2260
2261\typebuffer[h]
2262
2263The clipping path is applied by saying:
2264
2265\startbuffer[i]
2266clip currentpicture to r ;
2267\stopbuffer
2268
2269\typebuffer[i]
2270
2271The result is quite acceptable:
2272
2273\startlinecorrection[blank]
2274\processMPbuffer[a,b,c,d,e,f,g,h,i]
2275\stoplinecorrection
2276
2277But, if you watch closely to how this graphic extends into to left margin of this
2278document, you will see that the bounding box is not yet right.
2279
2280\startlinecorrection[blank]
2281\processMPbuffer[a,b,c,d,e,f,g,h,i,x]
2282\stoplinecorrection
2283
2284\startbuffer[j]
2285setbounds currentpicture to r ;
2286\stopbuffer
2287
2288\typebuffer[j]
2289
2290We use the same path \type {r} to correct the bounding box.
2291
2292\startlinecorrection[blank]
2293\processMPbuffer[a,b,c,d,e,f,g,h,i,j,x]
2294\stoplinecorrection
2295
2296There are a few subtle points involved, like setting the \type {linejoin}
2297variable. If we had not set it to \type {mitered}, we would have got round
2298corners. We don't set the \type {linecap}, because a flat cap would not extend
2299far enough into the touching curve and would have left a small hole. The next
2300example shows what happens if we set these variables to the wrong values:
2301
2302\startbuffer[bb]
2303linejoin := rounded ; linecap := mitered ;
2304\stopbuffer
2305
2306\startlinecorrection[blank]
2307\processMPbuffer[a,b,bb,c,d,e,f,g,h,i,j]
2308\stoplinecorrection
2309
2310In fact we misuse the fact that both curves overlay each other.
2311
2312\startbuffer[f]
2313draw p withcolor nsblue ; draw q withcolor .625white ;
2314\stopbuffer
2315
2316\startlinecorrection[blank]
2317\processMPbuffer[a,b,c,d,e,f,g,h,i,j]
2318\stoplinecorrection
2319
2320The complete logo definition is a bit more extensive because we also want to add
2321a background. Because we need to clip the blue foreground graphic, we must
2322temporarily store it when we fill the background.
2323
2324\typebuffer[ns]
2325
2326For practical use it makes sense to package this definition in a macro to which
2327we pass the dimensions.
2328
2329\stopsection
2330
2331\startsection[title={Music sheets}]
2332
2333The next example demonstrates quite some features. Imagine that we want to make
2334us a couple of sheets so that we can write a musical masterpiece. Let's also
2335forget that \TEX\ can draw lines, which means that somehow we need to use
2336\METAPOST.
2337
2338Drawing a bar is not that complicated as the following code demonstrates.
2339
2340\startbuffer
2341\startusableMPgraphic{bar}
2342  vardef MusicBar (expr width, gap, linewidth, barwidth) =
2343    image
2344      ( interim linecap := butt ;
2345        for i=1 upto 5 :
2346          draw ((0,0)--(width,0)) shifted (0,(i-1)*gap)
2347            withpen pencircle scaled linewidth ;
2348        endfor ;
2349        for i=llcorner currentpicture -- ulcorner currentpicture ,
2350              lrcorner currentpicture -- urcorner currentpicture :
2351          draw i withpen pencircle scaled barwidth ;
2352        endfor ; )
2353  enddef ;
2354\stopusableMPgraphic
2355\stopbuffer
2356
2357\typebuffer \getbuffer
2358
2359We can define the sidebars a bit more efficient using two predefined subpaths:
2360
2361\starttyping
2362for i=leftboundary currentpicture, rightboundary currentpicture :
2363\stoptyping
2364
2365We define a macro \type {MusicBar} that takes four arguments. The first two
2366determine the dimensions, the last two concern the line widths. Now watch how we
2367can use this macro:
2368
2369\startbuffer
2370\includeMPgraphic{bar} ;
2371draw MusicBar (200pt, 6pt, 1pt, 2pt) ;
2372draw MusicBar (300pt, 6pt, 1pt, 2pt) shifted (0,-30pt) ;
2373\stopbuffer
2374
2375\typebuffer
2376
2377\startlinecorrection[blank]
2378\processMPbuffer
2379\stoplinecorrection
2380
2381As you can see in this example, the bar is a picture that can be transformed
2382(shifted in our case). However, a close look at the macro teaches us that it does
2383a couple of draws too. This is possible because we wrap the whole in an image
2384using the \type {image} macro. This macro temporary saves the current picture,
2385and at the end puts the old \type {currentpicture} under the new one.
2386
2387We wrap the whole in a \type {vardef}. This means that the image is returned as
2388if it was a variable. Actually, the last thing in a \type {vardef} should be a
2389proper return value, in our case a picture. This also means that we may not end
2390the \type {vardef} with a semi colon. So, when the content of the \type {vardef}
2391is expanded, we get something
2392
2393\starttyping
2394draw some_picture ... ;
2395\stoptyping
2396
2397Because we are still drawing something, we can add transform directives and set
2398attributes, like the color.
2399
2400The second \type {for} loop demonstrates two nice features. Instead of repeating
2401the draw operation by copying code, we apply it to a list, in our case a list of
2402paths. This list contains two simple line paths. Because an \type {image} starts
2403with a fresh \type {currentpicture}, we can safely use the bounding box data to
2404determine the height of the line.
2405
2406The next step in producing the sheets of paper is to put several bars on a page,
2407preferable with the width of the current text. This time we will use a reusable
2408graphic, because each bar is the same.
2409
2410\startbuffer
2411\startreusableMPgraphic{bars}
2412  \includeMPgraphic{bar} ;
2413  draw MusicBar (TextWidth, 6pt, 1pt, 2pt) withcolor .625yellow ;
2414\stopreusableMPgraphic
2415\stopbuffer
2416
2417\typebuffer \getbuffer
2418
2419\startlinecorrection[blank]
2420\reuseMPgraphic{bars}
2421\stoplinecorrection
2422
2423Instead of going through the trouble of letting \METAPOST\ calculate the positions
2424of the bars, we will use \TEX. We put 12 bars on a page and let \TEX\ take care
2425of the inter||bar spacing. Because we only want stretchable space between bars,
2426called glue in \TEX, we need to remove the last added glue.
2427
2428\startnotmode[screen]
2429
2430\startbuffer[music]
2431\startstandardmakeup[doublesided=no,page=]
2432  \dorecurse{15}{\reuseMPgraphic{bars}\vfill}\removelastskip
2433\stopstandardmakeup
2434\stopbuffer
2435
2436\stopnotmode
2437
2438\startmode[screen]
2439
2440\startbuffer[music]
2441\startstandardmakeup[doublesided=no,page=]
2442  \dorecurse{10}{\reuseMPgraphic{bars}\vfill}\removelastskip
2443\stopstandardmakeup
2444\stopbuffer
2445
2446\stopmode
2447
2448\typebuffer[music]
2449
2450\startusableMPgraphic{bar}
2451  vardef MusicBar (expr width, gap, linewidth, barwidth) =
2452    image
2453      ( interim linecap := butt ;
2454        for i=1 upto 5 :
2455          draw ((0,0)--(width,0))
2456            randomized (1pt,1.5pt)
2457            shifted (0,(i-1)*gap)
2458            withpen pencircle scaled linewidth ;
2459        endfor ;
2460        for i=llcorner currentpicture -- ulcorner currentpicture ,
2461              lrcorner currentpicture -- urcorner currentpicture :
2462          draw i randomized 2pt shifted (0,-1pt)
2463            withpen pencircle scaled barwidth ;
2464        endfor ; )
2465  enddef ;
2466\stopusableMPgraphic
2467
2468\startreusableMPgraphic{bars} % trigger a new one
2469  \includeMPgraphic{bar} ;
2470  draw MusicBar (TextWidth, 6pt, 1pt, 2pt) withcolor .625yellow ;
2471\stopreusableMPgraphic
2472
2473It may add to the atmosphere of handy||work if you slightly randomize the lines.
2474We leave it up to the reader to figure out how the code should be changed to
2475accomplish this.
2476
2477\startlinecorrection[blank]
2478\reuseMPgraphic{bars}
2479\stoplinecorrection
2480
2481The complete result is shown on the next page.
2482
2483\startpostponing
2484\getbuffer[music]
2485\stoppostponing
2486
2487\stopsection
2488
2489\startsection[title={The euro symbol}]
2490
2491When Patrick Gundlach posted a nice \METAPOST\ version of the euro symbol to the
2492\CONTEXT\ discussion list, he added the comment \quotation {The official
2493construction is ambiguous: how thick are the horizontal bars? How much do they
2494stick out to the left? Is this thing a circle or what? Are the angles on the left
2495side of the bars the same as the one on the right side? \unknown} The alternative
2496below is probably not as official as his, but permits a finetuning. You are
2497warned: whatever you try, the euro {\em is} and {\em will remain} an ugly symbol.
2498
2499We use a couple of global variables to control the euro shape within reasonable
2500bounds. Then we define two circles. Next we define a vertical line that we use in
2501a couple of cut and paste operations. Watch how the top left point of the outer
2502circle determines the slant of the line that we use to slice the vertical bars.
2503
2504\startbuffer[euro]
2505boolean trace_euro ; trace_euro := false ;
2506
2507vardef euro_symbol = image ( % begin_of_euro
2508
2509if unknown euro_radius   : euro_radius   := 2cm             ; fi ;
2510if unknown euro_width    : euro_width    := 3euro_radius/16 ; fi ;
2511if unknown euro_r_offset : euro_r_offset := euro_width      ; fi ;
2512if unknown euro_l_offset : euro_l_offset := euro_radius/32  ; fi ;
2513if unknown euro_l_shift  : euro_l_shift  := euro_r_offset   ; fi ;
2514if unknown euro_v_delta  : euro_v_delta  := euro_width/4    ; fi ;
2515
2516save
2517  outer_circle, inner_circle, hor_bar,
2518  right_line, right_slant, top_slant,  bot_slant,
2519  euro_circle, euro_topbar, euro_botbar ;
2520
2521path
2522  outer_circle, inner_circle, hor_bar,
2523  right_line, right_slant, top_slant, bot_slant,
2524  euro_circle, euro_topbar, euro_botbar ;
2525
2526outer_circle := fullcircle scaled euro_radius ;
2527inner_circle := fullcircle scaled (euro_radius-euro_width) ;
2528
2529if trace_euro : for i = outer_circle, inner_circle :
2530  draw i withpen pencircle scaled 1pt withcolor .5white ;
2531endfor ; fi ;
2532
2533right_line :=
2534  (lrcorner outer_circle -- urcorner outer_circle)
2535  shifted (-euro_r_offset,0) ;
2536
2537outer_circle := outer_circle cutbefore right_line ;
2538
2539right_slant :=
2540  point 0 of outer_circle
2541  -- origin shifted (0,ypart lrcorner outer_circle) ;
2542
2543euro_circle := buildcycle(outer_circle, right_line,
2544  reverse inner_circle, reverse right_slant) ;
2545
2546hor_bar := (-euro_radius,0) -- (euro_radius,0) ;
2547
2548top_slant :=
2549  right_slant shifted (-euro_radius+euro_r_offset-euro_l_offset,0) ;
2550
2551bot_slant :=
2552  top_slant shifted (0,-euro_l_shift) ;
2553
2554if trace_euro : for i = right_line, right_slant, top_slant, bot_slant :
2555  draw i withpen pencircle scaled 1pt withcolor .5white ;
2556endfor ; fi ;
2557
2558euro_topbar := buildcycle
2559  (top_slant, hor_bar shifted (0, euro_v_delta),
2560   right_slant, hor_bar shifted (0, euro_v_delta+euro_width/2)) ;
2561
2562euro_botbar := buildcycle
2563  (bot_slant, hor_bar shifted (0,-euro_v_delta),
2564   right_slant, hor_bar shifted (0,-euro_v_delta-euro_width/2)) ;
2565
2566for i = euro_circle, euro_topbar, euro_botbar :
2567  draw i withpen pencircle scaled 0 ;
2568endfor ;
2569for i = euro_circle, euro_topbar, euro_botbar :
2570  fill i withpen pencircle scaled 0 ;
2571endfor ;
2572
2573if trace_euro :
2574  drawpoints euro_circle withcolor red   ;
2575  drawpoints euro_topbar withcolor green ;
2576  drawpoints euro_botbar withcolor blue  ;
2577fi ;
2578
2579) enddef ; % end_of_euro
2580\stopbuffer
2581
2582\typebuffer[euro]
2583
2584We only set a parameter when it is not yet set. This has
2585the advantage that we don't have to set them when we change
2586one. This way of manipulating paths (cutting and building)
2587does not always work well because of rounding errors, but
2588here it does work.
2589
2590\startbuffer[demo]
2591euro_radius := 4cm ; trace_euro := true ; draw euro_symbol ;
2592\stopbuffer
2593
2594\typebuffer[demo]
2595
2596For educational purposes, we have added a bit of
2597tracing. When enabled, the euro shows up as:
2598
2599\startlinecorrection[blank]
2600\processMPbuffer[euro,demo]
2601\stoplinecorrection
2602
2603Of course it would be best to define the euro as one shape, but we won't go
2604though that process right now. By packaging the combined paths in an image, we
2605can conveniently color the euro symbol:
2606
2607\startbuffer[demo]
2608draw euro_symbol withcolor .625red ;
2609\stopbuffer
2610
2611\typebuffer[demo]
2612
2613\startlinecorrection[blank]
2614\processMPbuffer[euro,demo]
2615\stoplinecorrection
2616
2617You may wonder why we both draw and fill the euro, using a pen with zero width.
2618We've done this in order to demonstrate the \type {redraw} and \type {refill}
2619macros.
2620
2621\startbuffer[extra]
2622redraw currentpicture withpen pencircle scaled 4pt withcolor .625yellow ;
2623refill currentpicture withcolor .625white ;
2624setbounds currentpicture to boundingbox currentpicture enlarged 2pt ;
2625\stopbuffer
2626
2627\typebuffer[extra]
2628
2629\startlinecorrection[blank]
2630\processMPbuffer[euro,demo,extra]
2631\stoplinecorrection
2632
2633\stopsection
2634
2635\startsection[title={Killing time}]
2636
2637Not seldom \TEX\ users want to use this program and its meta||relatives as
2638general purpose tools, even at the cost of quite some effort or suboptimal
2639results. Imagine that you are under way from our planet to Mars. After a long
2640period of sleep you wake up and start wondering on what track you are. You even
2641start questioning the experts that send you on your way, so you pop open your
2642laptop, launch your editor and start metaposting.
2643
2644First you need to determine the begin and end points of your journey. For now it
2645is enough to know the relative angle of the paths that both planets follow as
2646well as the path themselves. We assume circular paths.
2647
2648\startbuffer
2649path a ; a := fullcircle scaled 3cm ;
2650path b ; b := fullcircle scaled 2cm rotated 120 ;
2651
2652draw a withpen pencircle scaled 1mm withcolor .625red ;
2653draw b withpen pencircle scaled 1mm withcolor .625yellow ;
2654
2655draw point 0 of a withpen pencircle scaled 2mm ;
2656draw point 0 of b withpen pencircle scaled 2mm ;
2657\stopbuffer
2658
2659\typebuffer
2660
2661The rotation 120 can be calculated from the relative starting points and time the
2662journey will take. Alternatively we can use the time along the path, but this
2663would be a bit more fuzzy later on. \footnote {In case you wonder why \METAPOST\
2664talks about the time on a path, you now have a cue.}
2665
2666\startlinecorrection[blank]
2667\processMPbuffer
2668\stoplinecorrection
2669
2670After a bit of playing with drawing paths between the two points, you decide to
2671make a macro. We want to feed the angle between the paths but also the connecting
2672path. So, we have to pass a path, but unfortunately we don't have direct access
2673to the points. By splitting the argument definition we can pass an expression
2674first, and a wildcard argument next.
2675
2676\startbuffer
2677\startuseMPgraphic{gamble}
2678def Gamble (expr rot) (text track) =
2679  path a ; a := fullcircle scaled 3cm ;
2680  path b ; b := fullcircle scaled 2cm rotated rot ;
2681
2682  pair aa ; aa := point 0 of a ;
2683  pair bb ; bb := point 0 of b ;
2684  path ab ; ab := track ;
2685
2686  draw a  withpen pencircle scaled 1mm withcolor .625red ;
2687  draw b  withpen pencircle scaled 1mm withcolor .625yellow ;
2688
2689  draw aa withpen pencircle scaled 2mm ;
2690  draw bb withpen pencircle scaled 2mm ;
2691
2692  drawarrow ab withpen pencircle scaled 1mm withcolor .625white ;
2693
2694  setbounds currentpicture to boundingbox a enlarged 2mm ;
2695  draw boundingbox currentpicture withpen pencircle scaled .25mm ;
2696enddef ;
2697\stopuseMPgraphic
2698\stopbuffer
2699
2700\typebuffer \getbuffer
2701
2702Because at this distance nobody will bother us with the thickness of the pen and
2703colors, we code them the hard way. We create our own universe by setting a fixed
2704boundingbox.
2705
2706We leave the Earth in the most popular way, straight upwards and after a few
2707cycles, we leave it parallel to the surface. The path drawn reminds much of the
2708trajectories shown in popular magazines.
2709
2710\startbuffer
2711\startMPcode
2712\includeMPgraphic{gamble} ;
2713Gamble(120, aa {(0,1)} .. bb) ;
2714\stopMPcode
2715\stopbuffer
2716
2717\typebuffer
2718
2719\startlinecorrection[blank] \getbuffer \stoplinecorrection
2720
2721According to \METAPOST, when we leave the Earth straight upwards and want a
2722smooth trajectory, we have to pass through outer space.
2723
2724\startbuffer
2725\startMPcode
2726\includeMPgraphic{gamble} ;
2727Gamble(120,aa {(1,0)} .. bb) ;
2728\stopMPcode
2729\stopbuffer
2730
2731\typebuffer
2732
2733\startlinecorrection[blank] \getbuffer \stoplinecorrection
2734
2735Given that we want a smooth path as well as a short journey, we can best follow
2736Mars' path. Here we face the risk that when we travel slower than Mars does, we
2737have a problem.
2738
2739\startbuffer
2740\startMPcode
2741\includeMPgraphic{gamble} ;
2742Gamble(120,aa {dir 90} .. {precontrol 0 of b rotated 90} bb) ;
2743\stopMPcode
2744\stopbuffer
2745
2746\typebuffer
2747
2748\startlinecorrection[blank] \getbuffer \stoplinecorrection
2749
2750We can even travel a shorter path when we leave Earth at the surface that faces
2751the point of arrival.
2752
2753\startbuffer
2754\startMPcode
2755\includeMPgraphic{gamble} ;
2756Gamble(120,aa .. {precontrol 0 of b rotated 90} bb) ;
2757\stopMPcode
2758\stopbuffer
2759
2760\typebuffer
2761
2762\startlinecorrection[blank] \getbuffer \stoplinecorrection
2763
2764In the end we decide that although the trajectories look impressive, we will not
2765trust our lives to \METAPOST. A beautiful path is not neccessarily a good path.
2766But even then, this macro provides a nice way to experiment with directions,
2767controls and tensions.
2768
2769\stopsection
2770
2771% \startsection[title={Animations}]
2772%
2773% {\em Although \METAPOST\ is not that well suited for free hand drawings, you can
2774% use it to make stylistics animations.}
2775%
2776% \stopsection
2777
2778\startsection[title={Selective randomization}]
2779
2780In this document we have used a lot of randomization. Because \CONTEXT\ often
2781needs multiple runs to sort out cross references, positions, tables of contents,
2782and so on, being real random every run would result in endless runs to get things
2783right, because the size of graphics changes. This is prevented by storing the
2784random seed betweeen runs. You can remove the \type {tuc} file to get a new seed
2785(or run \type {context --purgeall}).
2786
2787Here is another example of randomization. This time we only randomize the control
2788points so the main shape sort of remains intact which can be handy when you use
2789such random shapes around text but still want a predictable size.
2790
2791\startbuffer
2792\startMPcode
2793fill fullcircle scaled 2cm
2794    randomizedcontrols 0.1cm
2795    withcolor darkred
2796    withtransparency (1,.5) ;
2797fill ((1cm,0)--(0,1cm)--(-1cm,0)--cycle)
2798    randomizedcontrols 0.1cm
2799    withcolor darkblue
2800    withtransparency (1,.5) ;
2801\stopMPcode
2802\stopbuffer
2803
2804\typebuffer
2805
2806\startlinecorrection[blank] \getbuffer \stoplinecorrection
2807
2808\startbuffer
2809\startMPcode
2810draw image (
2811    fill fullcircle scaled 2cm
2812        withcolor darkred
2813        withtransparency (1,.5) ;
2814    fill ((1cm,0)--(0,1cm)--(-1cm,0)--cycle)
2815        withcolor darkblue
2816        withtransparency (1,.5) ;
2817) randomizedcontrols 0.1cm ;
2818\stopMPcode
2819\stopbuffer
2820
2821\typebuffer
2822
2823\startlinecorrection[blank] \getbuffer \stoplinecorrection
2824
2825\stopsection
2826
2827\startsection[title=Snapping]
2828
2829There are quite some helpers in \METAFUN\ and I must admit that I forgot
2830about most. Some just ended up in the core because they can be useful, others
2831serve as illustration. Here's one of them: \type {snapped}. First we define
2832a few helpers that we then use to check out a few shapes.
2833
2834\startbuffer
2835\startMPdefinitions
2836def ShowSnapGrid(text shape) =
2837    fill (shape xsized 77mm) withcolor white/3 ;
2838    draw image (
2839        for i=10mm step 5mm until 100mm :
2840            draw fullsquare scaled i ;
2841        endfor ;
2842    ) withcolor 2white/3 ;
2843    drawpoints (shape xsized 77mm) withcolor black ;
2844enddef ;
2845
2846vardef SnapShape expr shape =
2847    image (
2848        draw       shape ;
2849        drawpoints shape ;
2850    )
2851enddef ;
2852
2853vardef ShowSnapShape expr shape =
2854    ShowSnapGrid(shape);
2855
2856    draw SnapShape(shape xsized 77mm snapped -5mm      ) withcolor red ;
2857    draw SnapShape(shape xsized 77mm snapped  5mm      ) withcolor red ;
2858    draw SnapShape(shape xsized 77mm snapped (5mm,10mm)) withcolor green ;
2859    draw SnapShape(shape xsized 77mm snapped (5mm,15mm)) withcolor blue ;
2860    draw SnapShape(shape xsized 77mm snapped (5mm,20mm)) withcolor yellow ;
2861enddef ;
2862\stopMPdefinitions
2863\stopbuffer
2864
2865\typebuffer \getbuffer
2866
2867In \in {figures} [fig:snapper:1], \in [fig:snapper:2] and \in [fig:snapper:3] we
2868see how the original shape gets snapped on the grid. Of course in more complex
2869images the direction of the snapping can change the result in an unwanted way,
2870like overlapping shapes that obscure others, but normally this snapping is only
2871useful for simple predictable cases (like title pages).
2872
2873\startplacefigure[reference=fig:snapper:1,title={Messing with \type{fullcircle}.}]
2874\startMPcode
2875    ShowSnapShape(fullcircle);
2876\stopMPcode
2877\stopplacefigure
2878
2879\startplacefigure[reference=fig:snapper:2,title={\type{fullsquare}}]
2880\startMPcode
2881    ShowSnapShape(fullsquare);
2882\stopMPcode
2883\stopplacefigure
2884
2885\startplacefigure[reference=fig:snapper:3,title={\type{fulltriangle}}]
2886\startMPcode
2887    ShowSnapShape(fulltriangle);
2888\stopMPcode
2889\stopplacefigure
2890
2891\stopsection
2892
2893\startsection[title=Arrowheads]
2894
2895Arrows are actually drawn quite well in \METAPOST, as the arrowheads nicely adapt
2896to the direction of the point where the arrowhead is attached. There are however
2897some limitations as the following examples demonstrate: arrows don't work well
2898with transparency and you can probably figure out why. Alan Braslau came up with
2899an extension that allows to set the dimple of the head. You can see all this
2900in \in {figure} [fig:arrowheads].
2901
2902\startbuffer[a]
2903numeric unit ; unit := mm ;
2904
2905drawoptions(withcolor .6blue withtransparency (1,.25)) ;
2906
2907pickup pencircle scaled 2unit ; ahlength := 6unit ;
2908
2909picture p ; p := image (
2910    drawarrow reverse fullcircle rotated - 5 scaled 50unit ;
2911    drawarrow reverse fullcircle rotated -10 scaled 30unit ;
2912) shifted ( -45unit, 0unit) ;
2913
2914for i=0 step 90 until 360 : draw p rotated i ; endfor ;
2915
2916currentpicture := currentpicture shifted - center currentpicture ;
2917
2918p := currentpicture ; p := image (
2919    draw llcorner p -- center p ;
2920    drawarrow llcorner p -- 0.875[llcorner p,center p] ;
2921) ;
2922
2923for i=0 step 90 until 360 : draw p rotated i ; endfor ;
2924
2925clip currentpicture to boundingbox (fullcircle scaled 80unit) ;
2926
2927if lua.mp.mode("screen") :
2928    currentpicture := currentpicture ysized .4TextHeight ;
2929else :
2930    currentpicture := currentpicture xsized .4TextWidth ;
2931fi ;
2932\stopbuffer
2933
2934\typebuffer[a]
2935
2936\startbuffer[b]
2937    resetarrows ;
2938\stopbuffer
2939
2940\startbuffer[a1]
2941    ahvariant := 1 ;
2942\stopbuffer
2943\startbuffer[a2]
2944    ahvariant := 2 ;
2945\stopbuffer
2946
2947\startbuffer[a3]
2948    ahvariant := 1 ; ahdimple  := 1/2 ;
2949\stopbuffer
2950\startbuffer[a4]
2951    ahvariant := 1 ; ahdimple  := 1 ;
2952\stopbuffer
2953\startbuffer[a5]
2954    ahvariant := 1 ; ahdimple  := 5/2 ;
2955\stopbuffer
2956
2957\startplacefigure[reference=fig:arrowheads,title=The way arrowheads are constructed.]
2958    \doifelsemode {screen} {
2959        \setupcombination[nx=3,ny=2]
2960    } {
2961        \setupcombination[nx=2,ny=3]
2962    }
2963    \startcombination[distance=2em]
2964        {\processMPbuffer[a,   b]} {\tttf ahvariant=0}
2965        {\processMPbuffer[a1,a,b]} {\tttf ahvariant=1}
2966        {\processMPbuffer[a2,a,b]} {\tttf ahvariant=2}
2967        {\processMPbuffer[a3,a,b]} {\tttf ahvariant=1, ahdimple=1/2}
2968        {\processMPbuffer[a4,a,b]} {\tttf ahvariant=1, ahdimple=1}
2969        {\processMPbuffer[a5,a,b]} {\tttf ahvariant=1, ahdimple=5/2}
2970    \stopcombination
2971\stopplacefigure
2972
2973\stopsection
2974
2975\startsection[title=Teaser]
2976
2977Sometimes, when playing with \METAPOST\ you run into interesting cases. Here is
2978one. The result is shown in \in {figure} [fig:teaser:1].
2979
2980\startbuffer
2981\startusableMPgraphic{BackgroundTeaser}
2982    fill OverlayBox enlarged 1mm withcolor darkyellow ; % bleed
2983    path p ; p := OverlayBox enlarged  -5mm ;
2984    path q ; q := OverlayBox enlarged -10mm ;
2985    fill q withcolor white ;
2986    drawoptions(withcolor darkred) ;
2987    fill reverse topboundary    q -- topboundary    p -- cycle ;
2988    fill reverse bottomboundary q -- bottomboundary p -- cycle ;
2989    drawoptions(withcolor darkgreen) ;
2990    fill reverse leftboundary   q -- leftboundary   p -- cycle ;
2991    fill reverse rightboundary  q -- rightboundary  p -- cycle ;
2992\stopusableMPgraphic
2993
2994\defineoverlay
2995  [BackgroundTeaser]
2996  [\useMPgraphic{BackgroundTeaser}]
2997
2998\framed
2999  [frame=off,
3000   offset=15mm,
3001   background=BackgroundTeaser,
3002   align=normal]
3003  {\input knuth }
3004\stopbuffer
3005
3006\typebuffer
3007
3008\startplacefigure[reference=fig:teaser:1,title=Can you guess what happens here?]
3009    \getbuffer
3010\stopplacefigure
3011
3012\stopsection
3013
3014\startsection[title={Lists}]
3015
3016For some specific purpose I needed to sort a list of paths and therefore
3017\METAFUN\ comes with a quick sort macro. Its working can be demonstrated by an
3018example.
3019
3020\startbuffer[a]
3021pair p[], pp[] ; numeric n ; n := 25 ;
3022for i=1 upto n : p[i] := origin randomized 4cm ; endfor ;
3023\stopbuffer
3024
3025\startbuffer[b]
3026copylist(p,pp) ; % unsorted
3027drawarrow listtolines(pp) shifted (  0,0) withcolor darkblue ;
3028\stopbuffer
3029
3030\startbuffer[c]
3031copylist(p,pp) ; sortlist(pp)() ; % sorted
3032drawarrow listtolines(pp) shifted (300,0) withcolor darkyellow ;
3033\stopbuffer
3034
3035\startbuffer[d]
3036copylist(p,pp) ; sortlist(pp)(xpart) ;
3037drawarrow listtolines(pp) shifted (100,0) withcolor darkred ;
3038
3039\stopbuffer
3040\startbuffer[e]
3041copylist(p,pp) ; sortlist(pp)(ypart) ;
3042drawarrow listtolines(pp) shifted (200,0) withcolor darkgreen ;
3043\stopbuffer
3044
3045\startbuffer[f]
3046vardef whow expr p = (xpart p + ypart p) enddef ;
3047
3048copylist(p,pp) ; sortlist(pp)(whow) ;
3049drawarrow listtolines(pp) shifted (400,0) withcolor darkcyan ;
3050\stopbuffer
3051
3052\startbuffer[g]
3053vardef whow expr p = (xpart p ++ ypart p) enddef ;
3054
3055copylist(p,pp) ; sortlist(pp)(whow) ;
3056drawarrow listtolines(pp) shifted (500,0) withcolor darkmagenta ;
3057\stopbuffer
3058
3059\typebuffer[a,b,c,d,e,f,g]
3060
3061The result of this code is shown in \in {figure} [fig:sorting].
3062
3063\startplacefigure[reference=fig:sorting,title={Using the sorter.}]
3064    \startcombination[3*2]
3065        {\processMPbuffer[a,b]} {\tttf unsorted}
3066        {\processMPbuffer[a,c]} {\tttf sorted}
3067        {\processMPbuffer[a,d]} {\tttf xpart}
3068        {\processMPbuffer[a,e]} {\tttf ypath}
3069        {\processMPbuffer[a,f]} {\tttf xpart p + ypart p}
3070        {\processMPbuffer[a,g]} {\tttf xpart p ++ ypart p}
3071    \stopcombination
3072\stopplacefigure
3073
3074There is a helper that converts a list of paths into a shape that covers all
3075of them. In \in {figure} [fig:shapedlist] three shaped lists are shown.
3076
3077\startbuffer[a]
3078    def ShowShape(expr e) =
3079        draw image (
3080
3081            save p ; path p[] ;
3082
3083            def MakeShape(expr i,w,h,x,y) =
3084                p[i] := e
3085                    xysized ((w,h) randomized (2mm,1mm))
3086                    shifted ((x,y) randomized (2mm,1mm)) ;
3087            enddef ;
3088
3089            MakeShape(1,40mm,6mm,10mm,  0mm) ;
3090            MakeShape(2,50mm,5mm, 5mm,-10mm) ;
3091            MakeShape(3,20mm,8mm,30mm,-20mm) ;
3092            MakeShape(4,55mm,5mm,10mm,-30mm) ;
3093            MakeShape(5,55mm,5mm, 5mm,-50mm) ;
3094
3095            save s ; path s ; s := shapedlist(p) ; drawarrow  s ;
3096
3097            linejoin := butt ;
3098
3099            for i=1 upto 5 :
3100                fill p[i] withcolor .75white withtransparency (1,.5) ;
3101                draw thetextext("\tttf " & decimal i, center p[i]) ;
3102            endfor ;
3103
3104        ) ysized 4cm ;
3105    enddef ;
3106\stopbuffer
3107
3108\typebuffer[a]
3109
3110\startbuffer[b]
3111ShowShape(unitsquare)
3112\stopbuffer
3113
3114\startbuffer[c]
3115ShowShape(unitcircle)
3116\stopbuffer
3117
3118\startbuffer[d]
3119ShowShape(unittriangle)
3120\stopbuffer
3121
3122\startplacefigure[reference=fig:shapedlist,title={The \type {shapedlist} macro returns the envelope that covers all the paths in the list.}]
3123    \startcombination[3*1]
3124        {\processMPbuffer[a,b]} {\tttf unitsquare}
3125        {\processMPbuffer[a,c]} {\tttf unitcircle}
3126        {\processMPbuffer[a,d]} {\tttf unittriangle}
3127    \stopcombination
3128\stopplacefigure
3129
3130\stopsection
3131
3132\startsection[title=Table cells]
3133
3134Sometimes a standard \CONTEXT\ feature doesn't work out as expected. Take the
3135following table:
3136
3137\startbuffer
3138\bTABLE[frame=on,framecolor=blue,rulethickness=1pt]
3139    \bTR
3140        \bTD test \eTD
3141        \bTD test \eTD
3142        \bTD test \eTD
3143        \bTD[framecolor=magenta] test \eTD
3144        \bTD test \eTD
3145        \bTD test \eTD
3146    \eTR
3147    \bTR
3148        \bTD test \eTD
3149        \bTD[framecolor=red] test \eTD
3150        \bTD test \eTD
3151        \bTD test \eTD
3152        \bTD test \eTD
3153        \bTD[framecolor=green] test \eTD
3154    \eTR
3155\eTABLE
3156\stopbuffer
3157
3158\typebuffer
3159
3160Because cells are drawn top|-|down and left|-|right a next cell border
3161overruns the previous one.
3162
3163\startlinecorrection
3164\getbuffer
3165\stoplinecorrection
3166
3167\startbuffer
3168\bTABLE[frame=on,framecolor=blue,rulethickness=1pt]
3169    \bTR
3170        \bTD test \eTD
3171        \bTD test \eTD
3172        \bTD test \eTD
3173        \bTD[framecolor=magenta,frameoffset=-.5pt] test \eTD
3174        \bTD test \eTD
3175        \bTD test \eTD
3176    \eTR
3177    \bTR
3178        \bTD test \eTD
3179        \bTD[framecolor=red,frameoffset=-.5pt] test \eTD
3180        \bTD test \eTD
3181        \bTD test \eTD
3182        \bTD test \eTD
3183        \bTD[framecolor=green,frameoffset=-.5pt] test \eTD
3184    \eTR
3185\eTABLE
3186\stopbuffer
3187
3188You can try this:
3189
3190\typebuffer
3191
3192which gives us something that is not okay either for cells that touch an edge:
3193
3194\startlinecorrection
3195\getbuffer
3196\stoplinecorrection
3197
3198but we can cheat:
3199
3200\startlinecorrection
3201\framed
3202  [offset=overlay,
3203   frameoffset=.5pt,
3204   framecolor=blue,
3205   rulethickness=1pt]
3206  {\getbuffer}
3207\stoplinecorrection
3208
3209This is achieved by framing the whole table:
3210
3211\starttyping
3212\framed
3213  [offset=overlay,
3214   frameoffset=.5pt,
3215   framecolor=blue,
3216   rulethickness=1pt]
3217  {...}
3218\stoptyping
3219
3220\startbuffer
3221\startuseMPgraphic{cell:innerframe}{innercolor}
3222    draw OverlayBox enlarged -1.5OverlayLineWidth
3223        withpen pensquare scaled OverlayLineWidth
3224        withcolor \MPvar{innercolor} ;
3225\stopuseMPgraphic
3226
3227\defineoverlay
3228  [innerframe]
3229  [{\uniqueMPgraphic{cell:innerframe}%
3230      {innercolor=\framedparameter{innercolor}}}]
3231
3232\bTABLE[frame=on,framecolor=blue,rulethickness=1pt,innercolor=magenta]
3233    \bTR
3234        \bTD test \eTD
3235        \bTD test \eTD
3236        \bTD test \eTD
3237        \bTD[background=innerframe] test \eTD
3238        \bTD test \eTD
3239        \bTD test \eTD
3240    \eTR
3241    \bTR
3242        \bTD test \eTD
3243        \bTD[background=innerframe,innercolor=red] test \eTD
3244        \bTD test \eTD
3245        \bTD test \eTD
3246        \bTD test \eTD
3247        \bTD[background=innerframe,innercolor=green] test \eTD
3248    \eTR
3249\eTABLE
3250\stopbuffer
3251
3252A \METAPOST\ alternative is also possible and it gives a bit nicer
3253interface too:
3254
3255\typebuffer
3256
3257We get:
3258
3259\startlinecorrection
3260\getbuffer
3261\stoplinecorrection
3262
3263\stopsection
3264
3265\startsection[title=Educational]
3266
3267I made this example long ago, when some family member had to learn tables by
3268heart. For some reason, at school, this is made into a complex issue, with tricks
3269and such, even it if only involves only a few numbers. My own experience (if I
3270remember right) was that some of these numbers are trivial, and that there is
3271quite some symmetry, so in practice only a quarter needs to be remembered. And,
3272assuming that you can easily deduct the trivial cases, one can just calculate the
3273rest if needed.
3274
3275\startbuffer
3276\start \ttbf \startMPcode
3277  def MyDraw(expr i, j, c) =
3278    fill fullsquare shifted (i,j) withcolor c withtransparency (1,.5) ;
3279  enddef ;
3280
3281  for i = 1 upto 10 :
3282  for j = 1 upto 10 : MyDraw( i,  -j, "middlered"   ) ; endfor ; endfor ;
3283
3284  for j = 1 upto 10 : MyDraw( 1,  -j, "middleblue"  ) ; endfor ;
3285  for i = 1 upto 10 : MyDraw( i, -10, "middlegreen" ) ; endfor ;
3286  for i = 1 upto 10 : MyDraw( i,  -1, "middleyellow") ; endfor ;
3287  for j = 1 upto 10 : MyDraw(10,  -j, "middlecyan"  ) ; endfor ;
3288  for j = 1 upto 10 : MyDraw( 5,  -j, "middlegray"  ) ; endfor ;
3289  for j = 1 upto 10 : MyDraw( j,  -j, "middlegray"  ) ; endfor ;
3290
3291  draw image ( for i = 1 upto 10 : for j = 1 upto 10 :
3292    draw textext(decimal (i*j)) ysized .25 shifted (i,-j) ;
3293  endfor ; endfor ; ) withcolor white ;
3294
3295  currentpicture := currentpicture ysized 10cm ;
3296\stopMPcode \stop
3297\stopbuffer
3298
3299\typebuffer
3300
3301\startplacefigure[title=Overlapping glyphs,reference=fig:tentable]
3302    \getbuffer
3303\stopplacefigure
3304
3305Here we use both transparency and colors to stress the reduction of cases. The
3306named colors resolve to ones defined at the \TEX\ end. We see the redndering
3307\in {figure} [fig:tentable].
3308
3309\startsection[title=Glyph magic]
3310
3311The next example is the result of a tread on the mailing list. After Henri Menke
3312posted a some glyph overlap code, I made a variant that more suited the way we do
3313it in \METAFUN. In the meantime Floris van Maanen had found out that some glyphs
3314need a more inventive solution so after that the code evolved. By then the \type
3315{outlinetext}, \type {drawoutlinetext} and \type {filloutlinetext} helpers had
3316been added to the code base.
3317
3318Because this is complicated stuff, we just show the two solutions. The first one
3319is a relative simple one, the second one uses an approach suggested by Alan
3320Braslau and therefore uses some of the code that can be found in the \type
3321{crossingunder} macro.
3322
3323\startbuffer
3324\startMPdefinitions
3325def ShowOverlapInOutlinesA(expr first, second) =
3326  path p_i, p_j, s_i, s_j ;
3327  numeric n_i, n_j, index ;
3328  pair found ;
3329  index := 0 ;
3330  for i within first :
3331    for j within second :
3332      p_i := pathpart i ; n_i := length(p_i) ;
3333      p_j := pathpart j ; n_j := length(p_j) ;
3334      for ii = 0 upto n_i - 1 :
3335        s_i := subpath(ii,ii+1) of p_i ;
3336        for jj = 0 upto n_j - 1 :
3337          s_j := subpath(jj,jj+1) of p_j ;
3338          found := s_i intersection_point s_j ;
3339          if intersection_found :
3340            index := index + 1 ;
3341            drawdot found
3342              withpen pencircle scaled 4 withcolor white ;
3343            draw textext("\strut\ttbf " & decimal index) ysized 3
3344              shifted found ;
3345          fi ;
3346        endfor ;
3347      endfor ;
3348    endfor ;
3349  endfor ;
3350enddef ;
3351\stopMPdefinitions
3352\stopbuffer
3353
3354\typebuffer \getbuffer
3355
3356This is the solution based on \type {crossingunder}, a macro that has been
3357introduced as part of Alan's neat node module.
3358
3359\startbuffer
3360\startMPdefinitions
3361def ShowOverlapInOutlinesB(expr first, second) =
3362  begingroup ;
3363    save p, q, n, t, a, b, c, bcuttings, hold, found ;
3364    path p, q ;
3365    numeric n, hold ;
3366    path a, b, c, bcuttings ;
3367    pair found ;
3368    c := makepath(currentpen scaled crossingscale) ;
3369    for f within first :
3370      numeric t[];
3371      path hold[];
3372      t[0] := n := hold := 0 ;
3373      for s within second :
3374        p := pathpart f ;
3375        q := pathpart s ;
3376        a := p ;
3377        for i=1 upto crossingnumbermax : % safeguard
3378          clearxy ; z = a intersectiontimes q ;
3379          if x < 0 :
3380            exitif hold < 1 ;
3381            a := hold[hold] ; hold := hold - 1 ;
3382            clearxy ; z = a intersectiontimes q ;
3383          fi
3384          (t[incr n], whatever) = p intersectiontimes point x of a ;
3385          if x = 0 :
3386            a := a cutbefore c shifted point x of a ;
3387          elseif x = length a :
3388            a := a cutafter  c shifted point x of a ;
3389          else : % before or after?
3390            b := subpath (0,x)        of a cutafter  c shifted point x of a ;
3391            bcuttings := cuttings ;
3392            a := subpath (x,length a) of a cutbefore c shifted point x of a ;
3393            clearxy ; z = a intersectiontimes q ;
3394            if x < 0 :
3395              a := b ;
3396              cuttings := bcuttings ;
3397            elseif length bcuttings > 0 :
3398              clearxy ; z = b intersectiontimes q ;
3399              if x >= 0 :
3400                hold[incr hold] := b ;
3401              fi
3402            fi
3403          fi
3404          if length cuttings = 0 :
3405            exitif hold < 1 ;
3406            a := hold[hold] ; hold := hold - 1 ;
3407          fi
3408        endfor ;
3409      endfor ;
3410      t[incr n] = length p ;
3411      for i=1 upto n :
3412        found := point t[i] of p ;
3413        drawdot found
3414          withpen pencircle scaled 4 withcolor white ;
3415        draw textext("\strut\ttbf " & decimal i) ysized 3
3416          shifted found ;
3417      endfor ;
3418    endfor ;
3419  endgroup ;
3420enddef ;
3421\stopMPdefinitions
3422\stopbuffer
3423
3424\typebuffer \getbuffer
3425
3426We demonstrate the differences with an example. The result can be seen in
3427\in {figure} [fig:overlapping:a].
3428
3429\startbuffer
3430\startcombination
3431  {\startMPcode
3432     picture first, second ;
3433     first  := outlinetext.p("N") ; first  := first  scaled 10 ;
3434     second := outlinetext.p("T") ; second := second scaled 10 ;
3435     second := second rotatedaround(center second, 5) shifted (1,-1) ;
3436     filloutlinetext(first ) withcolor .5[darkblue,white] ;
3437     filloutlinetext(second) withcolor .5[darkred,white] ;
3438     drawoutlinetext(first ) ;
3439     drawoutlinetext(second) ;
3440     ShowOverlapInOutlinesA(first, second) ;
3441     addbackground withcolor darkgray ;
3442     currentpicture := currentpicture scaled 2.5 ;
3443   \stopMPcode} {Method A}
3444   {\startMPcode
3445      picture first, second ;
3446      first  := outlinetext.p("N") ; first  := first  scaled 10 ;
3447      second := outlinetext.p("T") ; second := second scaled 10 ;
3448      second := second rotatedaround(center second, 5) shifted (1,-1) ;
3449      filloutlinetext(first ) withcolor .5[darkgreen,white] ;
3450      filloutlinetext(second) withcolor .5[darkyellow,white] ;
3451      drawoutlinetext(first ) ;
3452      drawoutlinetext(second) ;
3453      ShowOverlapInOutlinesB(first, second) ;
3454      addbackground withcolor darkgray ;
3455      currentpicture := currentpicture scaled 2.5 ;
3456    \stopMPcode} {Method B}
3457\stopcombination
3458\stopbuffer
3459
3460\typebuffer
3461
3462\startplacefigure[title=Overlapping glyphs,reference=fig:overlapping:a]
3463    \getbuffer
3464\stopplacefigure
3465
3466We duplicate some code because the pictures will change in the process of
3467analyzing. Let's make a helper for that:
3468
3469\startbuffer
3470\startMPdefinitions
3471def ShowOverlap(expr f, s, m) =
3472  picture first, second ;
3473  first  := outlinetext.p(f) ; first  := first  scaled 10 ;
3474  second := outlinetext.p(s) ; second := second scaled 10 ;
3475
3476  filloutlinetext(first ) withcolor darkblue ;
3477  drawoutlinetext(first ) ;
3478
3479  filloutlinetext(second) withcolor darkred  ;
3480  drawoutlinetext(second) ;
3481
3482  if m == 2 :
3483    ShowOverlapInOutlinesB
3484  else :
3485    ShowOverlapInOutlinesA
3486  fi (first, second) ;
3487
3488  addbackground withcolor darkgray ;
3489  currentpicture := currentpicture ysized 4cm ;
3490enddef ;
3491\stopMPdefinitions
3492\stopbuffer
3493
3494\typebuffer \getbuffer
3495
3496Again we demonstrate the differences with some examples. The result can be seen in
3497\in {figure} [fig:overlapping:b].
3498
3499\startbuffer
3500  \startcombination[nx=3,ny=2]
3501    {\startMPcode ShowOverlap("N","T",1)                 ; \stopMPcode} {Method 1}
3502    {\startMPcode ShowOverlap("\$","Q",1)                ; \stopMPcode} {Method 1}
3503    {\startMPcode ShowOverlap("\tttf ABC","\tttf PQR",1) ; \stopMPcode} {Method 1}
3504    {\startMPcode ShowOverlap("N","T",2)                 ; \stopMPcode} {Method 2}
3505    {\startMPcode ShowOverlap("\$","Q",2)                ; \stopMPcode} {Method 2}
3506    {\startMPcode ShowOverlap("\tttf ABC","\tttf PQR",2) ; \stopMPcode} {Method 2}
3507  \stopcombination
3508\stopbuffer
3509
3510\typebuffer
3511
3512\startplacefigure[title=Overlapping glyphs,reference=fig:overlapping:b]
3513    \getbuffer
3514\stopplacefigure
3515
3516\stopsection
3517
3518\startsection[title=Hidden beauty]
3519
3520\index {hiding}
3521
3522The \type {hide} wraps its (text) argument in a group in such a way that whatever
3523happens is not interfering with its surrounding. This is comparable with what
3524\type {vardef} does except that there is nothing of value produced.
3525
3526\startbuffer
3527def mfun_curve_to_a = hide(let connect = mfun_curve_to_b ;) enddef ; def mfun_curve_to_b = .. enddef ;
3528def mfun_line_to_a  = hide(let connect = mfun_line_to_b  ;) enddef ; def mfun_line_to_b  = -- enddef ;
3529
3530def forcurve = hide(let connect = mfun_curve_to_a ;) for enddef;
3531def forline  = hide(let connect = mfun_line_to_a  ;) for enddef;
3532
3533draw image (
3534  draw forline  i = 0 upto 25 : connect(i,sin(i)) endfor
3535    withcolor darkblue
3536    withtransparency (1,.5) ;
3537  draw forcurve i = 0 upto 25 : connect(i,sin(i)) endfor
3538    withcolor darkyellow
3539    withtransparency (1,.5) ;
3540) xysized (TextWidth, 3cm) ;
3541\stopbuffer
3542
3543\typebuffer
3544
3545In this example we hide the assignment in the loop and not only define the \type
3546{connect} macro but also adept it after its first expansion. Usage is shown \in
3547{in } [fig:hide].
3548
3549\startplacefigure[title=Hiding assignments in a loop,reference=fig:hide]
3550    \processMPbuffer
3551\stopplacefigure
3552
3553\stopsection
3554
3555\stopchapter
3556
3557\stopcomponent
3558