1
2
3\startcomponent metafunbasics
4
5\environment metafunenvironment
6
7\startchapter[title={A few more details}]
8
9\startintro
10
11In this chapter we will see how to define a \METAPOST\ graphic, and how to
12include it in a document. Since the exact dimensions of graphics play an
13important role in the placement of a graphic, we will explore the way a bounding
14box is constructed.
15
16We will also pay attention to the usage of units and the side effects of scaling
17and shifting, since they can contradict our expectations in unexpected ways.
18Furthermore we will explore a few obscure areas.
19
20\stopintro
21
22\startsection[title={Making graphics}]
23
24\index{graphics}
25
26In this manual we will use \METAPOST\ in a rather straightforward way, and we
27will try to avoid complicated math as much as possible. We will do a bit of
28drawing, clipping, and moving around. Occasionally we will see some more
29complicated manipulations.
30
31When defined as standalone graphic, a \METAPOST\ file looks like this:
32
33\starttyping
34
35
36beginfig (7) ;
37 draw fullcircle scaled 3cm withpen pencircle scaled 1cm ;
38endfig ;
39
40end .
41\stoptyping
42
43The main structuring components in such a file are the \type {beginfig} and \type
44{endfig} macros. Like in a big story, the file has many subsentences, where
45each subsentence ends with a semicolon. Although the \type {end} command at
46the end of the file concludes the story, putting a period there is a finishing
47touch. Actually, after the \type {end} command you can put whatever text you
48wish, your comments, your grocery list, whatever. Comments in \METAPOST, prefixed
49by a percent sign, as in \typ {
50interpreter, but useful reminders for the programmer.
51
52Traditionally, if the file is saved as \type {yourfile.mp}, then the file is
53processed by \METAPOST\ by issuing the following command:
54
55\starttyping
56mpost yourfile
57\stoptyping
58
59after which you will have a graphic called \type {yourfile.7}, which contains a
60series of \POSTSCRIPT\ commands. Because \METAPOST\ does all the work, this file
61is efficient and compact. The number of distinct \POSTSCRIPT\ operators used is
62limited, which has the advantage that we can postprocess this file rather easily.
63Alternatively \METAPOST\ can generate \SVG\ output. It does when you say
64
65\starttyping
66outputformat := "svg" ;
67\stoptyping
68
69Here we will not go into details about this format. Even \POSTSCRIPT\ is not
70covered in detail as we use \METAPOST\ mostly in embedded form.
71
72We can view this file in a \POSTSCRIPT\ viewer like \GHOSTVIEW\ or convert the
73graphic to \PDF\ (using \type {mptopdf}) and view the result in a suitable \PDF\
74viewer like \ACROBAT. Of course, you can embed such a file in a \CONTEXT\
75document, using a command like:
76
77\starttyping
78\externalfigure[yourfile.7]
79\stoptyping
80
81We will go in more detail about embedding graphics in \in {chapter}
82[sec:embedding].
83
84If you have installed \CONTEXT, somewhere on your system there resides a file
85\type {mptool.mp}. If you make a standalone graphic, its best to put the
86following line at the top of your file:
87
88\starttyping
89input metafun ;
90\stoptyping
91
92By loading this file, the resulting graphic will provide a high resolution
93bounding box, which enables more accurate placement. The file also sets the \typ
94{prologues := 1} so that viewers like \GHOSTVIEW\ can refresh the file when it is
95changed.
96
97{\bf However!} When you use \METAPOST\ in \CONTEXT, you will not run the
98mentioned program at all: you embed your graphic in the document and we will
99discuss this later. You can still use separate files but then you process them as
100follows:
101
102\starttyping
103mtxrun script metapost somefile.mp
104\stoptyping
105
106Alternatively you can wrap the individual pictures in a \TEX\ file, say \type
107{yourfile.tex}:
108
109\starttyping
110\starttext
111 \startMPpage
112
113 \stopMPpage
114 \startMPpage
115
116 \stopMPpage
117\stoptext
118\stoptyping
119
120and then run:
121
122\starttyping
123context somefile.tex
124\stoptyping
125
126after which you can use the resulting \PDF\ file (if it has more pages you just
127filter the page from that file).
128
129Next we will introduce some more \METAPOST\ commands. From now on, we will omit
130the encapsulating \type {beginfig} and \type {endfig} macros. If you want to
131process these examples yourself, you should add those commands yourself, or if
132you use \CONTEXT\ you dont need them at all. You can for instance wrap them in a
133\type {\startMPpage} \unknown\ \type {\stopMPpage} environment if you want to
134play around.
135
136\startbuffer
137pickup pencircle scaled .5cm ;
138draw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
139draw origin withcolor .625yellow ;
140pickup pencircle scaled 1pt ;
141draw bbox currentpicture withcolor .625red ;
142\stopbuffer
143
144\typebuffer
145
146In this example we see a mixture of so called primitives as well as macros. A
147primitive is something hard coded, a builtin command, while a macro is a
148collection of such primitives, packaged in a way that they can be recalled
149easily. Where \type {scaled} is a primitive and \type {draw} a macro, \type
150{unitsquare} is a path variable, an abbreviation for:
151
152\starttyping
153unitsquare = (0,0) (1,0) (1,1) (0,1) cycle ;
154\stoptyping
155
156The double dash (\type {}) is also a macro, used to connect two points with a
157straight line segment. However, \type {cycle} is a primitive, which connects the
158last point of the unitsquare to the first on unitsquares path. Path variables
159must first be declared, as in:
160
161\starttyping
162path unitsquare ;
163\stoptyping
164
165A large collection of such macros is available when you launch \METAPOST. Consult
166the \METAPOST\ manual for details.
167
168\startlinecorrection[blank]
169\processMPbuffer
170\stoplinecorrection
171
172In the first line of our example, we set the drawing pen to \type {.5cm}. You can
173also specify such a dimension in other units, like points (\type {pt}). When no
174unit is provided, \METAPOST\ will use a big point (\type {bp}) , the \POSTSCRIPT\
175approximation of a point.
176
177The second line does just as it says: it draws a rectangle of certain dimensions
178in a certain color. In the third line we draw a colored dot at the origin of the
179coordinate system in which we are drawing. Finally, we set up a smaller pen and
180draw the bounding box of the current picture, using the variable \type
181{currentpicture}. Normally, all drawn shapes end up in this picture variable.
182
183\stopsection
184
185\startsection[title={Bounding boxes}]
186
187\index{boundingbox}
188
189If you take a close look at the last picture in the previous section, you will
190notice that the bounding box is larger than the picture. This is one of the nasty
191side effects of \METAPOSTs \type {bbox} macro. This macro draws a box, but with
192a certain offset. The next example shows how we can manipulate this offset.
193Personally I never use the \type {bbox} macro because this offset is rather
194annoying. Also, the \type {boundingbox} operator combined with \type {enlarged}
195can provide any offset you want.
196
197\startbuffer
198pickup pencircle scaled .5cm ;
199draw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
200path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
201draw bb withpen pencircle scaled 1pt withcolor .625red ;
202draw origin withpen pencircle scaled 5pt withcolor .625yellow ;
203\stopbuffer
204
205\typebuffer
206
207In the third line we define a path variable. We assign the current bounding box
208to this variable, but first we set the offset to zero. The last line demonstrates
209how to draw such a path. Instead of setting the pen as we did in the first line,
210we pass the dimensions directly.
211
212\startlinecorrection[blank]
213\processMPbuffer
214\stoplinecorrection
215
216Where \type {draw} draws a path, the \type {fill} macro fills one. In order to be
217filled, a path should be closed, which is accomplished by the \type {cycle}
218primitive, as we saw in constructing the \type {unitsquare} path.
219
220\startbuffer
221pickup pencircle scaled .5cm ;
222fill unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
223path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
224draw bb withpen pencircle scaled 1pt withcolor .625red ;
225draw origin withpen pencircle scaled 5pt withcolor .625yellow ;
226\stopbuffer
227
228\typebuffer
229
230This example demonstrates that when we fill the path, the resulting graphic is
231smaller. Where \type {draw} follows the center of a path, \type {fill} stays
232inside the path.
233
234\startlinecorrection[blank]
235\processMPbuffer
236\stoplinecorrection
237
238A third alternative is the \type {filldraw} macro. From the previous examples, we
239would expect a bounding box that matches the one of the drawn path.
240
241\startbuffer
242pickup pencircle scaled .5cm ;
243filldraw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
244path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
245draw bb withpen pencircle scaled 1pt withcolor .625red ;
246draw origin withpen pencircle scaled 5pt withcolor .625yellow ;
247\stopbuffer
248
249\typebuffer
250
251
252
253
254
255
256
257
258
259
260
261
262The resulting graphic has the bounding box of the fill. Note how the path,
263because it is stroked with a .5cm pen, extends beyond the border of the previous
264bounding box. The way this image shows up depends on the viewer (settings) you
265use to render the graphic. For example, in \GHOSTVIEW, if you disable clipping to
266the bounding box, only the positive quadrant of the graphic is shown. \footnote
267{Old versions of \METAPOST\ calculated the boundingbox differently for a \type
268{filldraw}: through the middle of the penpath.}
269
270\startlinecorrection[blank]
271\processMPbuffer
272\stoplinecorrection
273
274From the previous examples, you can conclude that the following alternative
275results in a proper bounding box:
276
277\startbuffer
278pickup pencircle scaled .5cm ;
279path p ; p := unitsquare xscaled 8cm yscaled 1cm ;
280fill p withcolor .625white ;
281draw p withcolor .625white ;
282path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
283draw bb withpen pencircle scaled 1pt withcolor .625red ;
284draw origin withpen pencircle scaled 5pt withcolor .625yellow ;
285\stopbuffer
286
287\typebuffer
288
289\startlinecorrection[blank]
290\processMPbuffer
291\stoplinecorrection
292
293The \CONTEXT\ distribution comes with a set of \METAPOST\ modules, one of which
294contains the \type {drawfill} macro, which provides the outer bounding box.
295\footnote {Starting from version 1.0 \METAPOST\ calculates the boundingbox
296differently and the distinction between \type {drawfill} and \type {filldraw} is
297gone. We keep them around both for compatibility.} Next we demonstrate its use in
298another, more complicated example.
299
300\startbuffer
301picture finalpicture ; finalpicture := nullpicture ;
302numeric n ; n := 0 ; bboxmargin := 0pt ;
303pickup pencircle scaled .5cm ;
304
305def shape =
306 unitsquare scaled 2cm withcolor .625white ;
307 draw bbox currentpicture
308 withpen pencircle scaled .5mm withcolor .625red ;
309 addto finalpicture also currentpicture shifted(n*3cm,0) ;
310 currentpicture := nullpicture ; n := n1 ;
311enddef ;
312
313fill shape ; draw shape ; filldraw shape ; drawfill shape ;
314
315currentpicture := finalpicture ;
316\stopbuffer
317
318\typebuffer
319
320Here we introduce a macro definition, \type {shape}. In \METAPOST, the start of a
321macro definition is indicated with the keyword \type {def}. Thereafter, you can
322insert other variables and commands, even other macro definitions. The keyword
323\type {enddef} signals the end of the macro definition. The result is shown in
324\in {figure} [fig:draws and fills]; watch the bounding boxes. Close reading of
325the macro will reveal that the \type {fill}, \type {draw}, \type {filldraw} and
326\type {drawfill} macros are applied to the first \type {unitsquare} path in the
327macro.
328
329\placefigure
330 [here]
331 [fig:draws and fills]
332 {A \type {fill}, \type {draw}, \type {filldraw} and \type
333 {drawfill} applied to the same square.}
334 {\processMPbuffer}
335
336In this macro, \type {bbox} calls a macro that returns the enlarged bounding box
337of a path. By setting \type {bboxmargin} we can influence how much the bounding
338box is enlarged. Since this is an existing variable, we dont have to allocate
339it, like we do with\type{numeric n}. Unless you take special precautions,
340variables are global by nature and persistent outside macros.
341
342\starttyping
343picture finalpicture ; finalpicture := nullpicture ;
344\stoptyping
345
346Just as \type {numeric} allocates an integer variable, the \type {picture}
347primitive allocates a picture data structure. We explicitly have to set this
348picture to nothing using the builtin primitive \type {nullpicture}.
349
350Later on, we will add the drawn paths as accumulated in \type {currentpicture} to
351this \type {finalpicture} in the following manner.
352
353\starttyping
354addto finalpicture also currentpicture shifted(n*3cm,0) ;
355\stoptyping
356
357Since we want to add a few more and dont want them to overlap, we shift them.
358Therefore we have to erase the current picture as well as increment the shift
359counter.
360
361\starttyping
362currentpicture := nullpicture ; n := n1 ;
363\stoptyping
364
365The \type {drawfill} macro is one of the \METAFUN\ macros. Another handy macro is
366\type {boundingbox}. When used instead of \type {bbox}, you dont have to set the
367margin to zero.
368
369\startbuffer
370drawoptions (withcolor .625white) ;
371path p ; p := unitsquare scaled 2cm ;
372fill p shifted (3cm,0) ;
373pickup pencircle scaled .5cm ; fill p shifted (6cm,0) ;
374fill p shifted (9cm,0) withpen pencircle scaled .5cm ;
375\stopbuffer
376
377\placefigure
378 [here]
379 [fig:more draws and fills]
380 {The influence of pens on \type {fill}.}
381 {\processMPbuffer}
382
383There is a subtle point in filling a shape. In \in {figure} [fig:more draws and
384fills] you see the influence of the pen on a \type {fill} operation. An indirect
385specification has no influence, and results in a filled rectangle with sharp
386corners. The third rectangle is drawn with a direct pen specification which
387results in a larger shape with rounds corners. However, the bounding box is the
388same in all three cases. The graphic is defined as follows. This time we dont
389use a (complicated) macro.
390
391\typebuffer
392
393When a graphic is constructed, its components end up in an internal data
394structure in a more or less layered way. This means that as long as a graphic is
395not flushed, you may consider it to be a stack of paths and texts with the paths
396being drawn or filled shapes or acting as clipping paths or bounding boxes.
397
398When you ask for the dimensions of a graphic the lower left and upper right
399corner are calculated using this stack. Because you can explicitly set bounding
400boxes, you can lie about the dimensions of a graphic. This is a very useful
401feature. In the rare case that you want to know the truth and nothing but the
402truth, you can tweak the \type {truecorners} numeric variable. We will
403demonstrate this with a few examples.
404
405\startbuffer
406fill fullcircle scaled 1cm withcolor .625yellow ;
407\stopbuffer
408
409\typebuffer
410
411\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection
412
413\startbuffer
414fill fullcircle scaled 1cm withcolor .625yellow ;
415setbounds currentpicture to boundingbox currentpicture enlarged 2mm ;
416\stopbuffer
417
418\typebuffer
419
420\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection
421
422\startbuffer
423fill fullcircle scaled 1cm withcolor .625yellow ;
424setbounds currentpicture to boundingbox currentpicture enlarged 2mm ;
425interim truecorners := 1 ;
426\stopbuffer
427
428\typebuffer
429
430\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection
431
432\startbuffer
433fill fullcircle scaled 1cm withcolor .625yellow ;
434interim truecorners := 1 ;
435setbounds currentpicture to boundingbox currentpicture enlarged 2mm ;
436\stopbuffer
437
438\typebuffer
439
440\startlinecorrection[blank]\ruledhbox{\processMPbuffer}\stoplinecorrection
441
442As you can see here, as soon as we set \type {truecorners} to1, the bounding box
443settings are ignored. \footnote {Normally you will use grouping to keep the
444interim local. In \METAFUN\ each figure restores this variable at the beginning.}
445
446There are two related macros: \type {bbwidth} and \type {bbheight} that you can
447apply to a path.
448
449\startbuffer
450fill unitcircle xscaled 4cm yscaled 2cm
451 withpen pencircle scaled 1mm withcolor .625red ;
452draw origin (bbwidth(currentpicture),0)
453 withpen pencircle scaled 1mm withcolor .625yellow ;
454draw origin (0,bbheight(currentpicture))
455 withpen pencircle scaled 1mm withcolor .625white ;
456\stopbuffer
457
458\typebuffer
459
460\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
461
462\stopsection
463
464Yet another helper is \type {boundingcircle}. Its effect can best be demonstrated with
465a few examples:
466
467\startbuffer[a]
468path p ; p := fullsquare scaled 2cm ;
469
470draw p withpen pencircle scaled 3mm withcolor .625white ;
471draw center p withpen pencircle scaled 3mm withcolor .625white ;
472draw boundingbox p withpen pencircle scaled 1mm withcolor .625red ;
473draw boundingcircle p withpen pencircle scaled 1mm withcolor .625yellow ;
474\stopbuffer
475
476\startbuffer[b]
477path p ; p := fullcircle scaled 2cm ;
478
479draw p withpen pencircle scaled 3mm withcolor .625white ;
480draw center p withpen pencircle scaled 3mm withcolor .625white ;
481draw boundingbox p withpen pencircle scaled 1mm withcolor .625red ;
482draw boundingcircle p withpen pencircle scaled 1mm withcolor .625yellow ;
483\stopbuffer
484
485\startbuffer[c]
486path p ; p := fulltriangle scaled 2cm ;
487
488draw p withpen pencircle scaled 3mm withcolor .625white ;
489draw center p withpen pencircle scaled 3mm withcolor .625white ;
490draw boundingbox p withpen pencircle scaled 1mm withcolor .625red ;
491draw boundingcircle p withpen pencircle scaled 1mm withcolor .625yellow ;
492\stopbuffer
493
494\typebuffer[a,b,c]
495
496You can consider the \type {boundingcircle} to be a round boundingbox.
497
498\startlinecorrection[blank]
499\startcombination[nx=3,ny=1,location=middle]
500 {\processMPbuffer[a]} {square}
501 {\processMPbuffer[b]} {circle}
502 {\processMPbuffer[c]} {triangle}
503\stopcombination
504\stoplinecorrection
505
506\startsection[title={Units}]
507
508\index{units}
509
510Like \TEX, \METAPOST\ supports multiple units of length. In \TEX, these units are
511hard coded and handled by the parser, where the internal unit of length is the
512scaled point (\type {sp}), something on the nanometer range. Because \METAPOST\
513is focused on \POSTSCRIPT\ output, its internal unit is the big point (\type
514{bp}). All other units are derived from this unit and available as numeric
515instead of hard coded.
516
517\starttyping
518mm = 2.83464 ; pt = 0.99626 ; dd = 1.06601 ; bp := 1 ;
519cm = 28.34645 ; pc = 11.95517 ; cc = 12.79213 ; in := 72 ;
520\stoptyping
521
522Careful reading reveals that only the \type {bp} and \type {in} are fixed, while
523the rest of the dimensions are scalar multiples of \type {bp}.
524
525Since we are dealing with graphics, the most commonly used dimensions are \type
526{pt}, \type {bp}, \type {mm}, \type {cm} and\type {in}.
527
528\startuseMPgraphic{pt}
529 fill fullsquare scaled 72.27pt withcolor .625yellow ;
530 fill fullcircle scaled 72.27pt withcolor white ;
531 label("72.27pt", center currentpicture) ;
532\stopuseMPgraphic
533\startuseMPgraphic{bp}
534 fill fullsquare scaled 72bp withcolor .625yellow ;
535 fill fullcircle scaled 72bp withcolor white ;
536 label("72bp", center currentpicture) ;
537\stopuseMPgraphic
538\startuseMPgraphic{mm}
539 fill fullsquare scaled 25.4mm withcolor .625yellow ;
540 fill fullcircle scaled 25.4mm withcolor white ;
541 label("25.4mm", center currentpicture) ;
542\stopuseMPgraphic
543\startuseMPgraphic{cm}
544 fill fullsquare scaled 2.54cm withcolor .625yellow ;
545 fill fullcircle scaled 2.54cm withcolor white ;
546 label("2.54cm", center currentpicture) ;
547\stopuseMPgraphic
548\startuseMPgraphic{in}
549 fill fullsquare scaled 1in withcolor .625yellow ;
550 fill fullcircle scaled 1in withcolor white ;
551 label("1in", center currentpicture) ;
552\stopuseMPgraphic
553
554\startlinecorrection[blank]
555\hbox to \hsize
556 {\useMPgraphic{pt}\hss
557 \useMPgraphic{bp}\hss
558 \useMPgraphic{mm}\hss
559 \useMPgraphic{cm}\hss
560 \useMPgraphic{in}}
561\stoplinecorrection
562
563The text in the center of the leftmost graphic is typeset by \METAPOST\ as a
564label.
565
566\starttyping
567fill fullsquare scaled 72.27pt withcolor .625yellow ;
568fill fullcircle scaled 72.27pt withcolor white ;
569label("72.27pt", center currentpicture) ;
570\stoptyping
571
572In \METAPOST\ the following lines are identical:
573
574\starttyping
575draw fullcircle scaled 100 ;
576draw fullcircle scaled 100bp ;
577\stoptyping
578
579You might be tempted to omit the unit, but this can be confusing, particularly if
580you also program in a language like \METAFONT, where the \type {pt} is the base
581unit. This means that a circle scaled to 100 in \METAPOST\ is not the same as a
582circle scaled to 100 in \METAFONT. Consider the next definition:
583
584\startbuffer
585pickup pencircle scaled 0 ;
586fill unitsquare
587 xscaled 400pt yscaled .5cm withcolor .625red ;
588fill unitsquare
589 xscaled 400bp yscaled .5cm withcolor .625yellow ;
590drawoptions(withcolor white) ;
591label.rt("400 pt", origin shifted (0, .25cm)) ;
592label.rt("400 bp", origin shifted (0, .25cm)) ;
593\stopbuffer
594
595\typebuffer
596
597When processed, the difference between a \type {pt} and \type {bp} shows rather
598well. Watch how we use \type {.rt} to move the label to the right; you can
599compare this with \TEXs macro \type {\rlap}. You might want to experiment with
600\type {.lft}, \type {.top}, \type {.bot}, \type {.ulft}, \type {.urt}, \type
601{.llft} and \type {.lrt}.
602
603The difference between both bars is exactly \scratchdimen = 400 bp
604\advance\scratchdimen by 400 pt \the \scratchdimen \space (as calculated by
605\TEX).
606
607\startlinecorrection[blank]
608\processMPbuffer
609\stoplinecorrection
610
611Where \TEX\ is anchored in tradition, and therefore more or less uses the \type
612{pt} as the default unit, \METAPOST, much like \POSTSCRIPT, has its roots in the
613computer sciences. There, to simplify calculations, an inch is divided in 72 big
614points, and .72pt is sacrificed.
615
616When you consider that \POSTSCRIPT\ is a high end graphic programming language,
617you may wonder why this sacrifice was made. Although the difference between \type
618{1bp} and \type {1pt} is miniscule, this difference is the source of much
619(unknown) confusion. When \TEX\ users talk about a \type {10pt} font, a desktop
620publisher hears \type {10bp}. In a similar vein, when we define a papersize
621having a width of \type {600pt} and a height of \type {450pt}, which is papersize
622\type {S6} in \CONTEXT, a \POSTSCRIPT\ or \PDF\ viewer will report slightly
623smaller values as page dimensions. This is because those programs claim the \type
624{pt} to be a \type {bp}. [This confusion can lead to interesting discussions with
625desktop publishers when they have to use \TEX. They often think that their demand
626of a baseline distance of \type {13.4} is met when we set it to \type {13.4pt},
627while actually they were thinking of \type {13.4bp}, which of course in other
628programs is specified using a \type {pt} suffix.]
629
630Therefore, when embedding graphics in \CONTEXT, we strongly recommend that you
631use \type {pt} as the base unit instead. The main reason why we spend so many
632words on this issue is that, when neglected, large graphics may look inaccurate.
633Actually, when taken care of, it is one of the (many) reasons why \TEX\ documents
634always look so accurate. Given that the eye is sensitive to distortions of far
635less than \type {1pt}, you can be puzzled by the fact that many drawing programs
636only provide a bounding box in rounded units. Thereby, they round to the next
637position, to prevent unwanted cropping. For some reason this low resolution has
638made it into the high end \POSTSCRIPT\ standard.
639
640In \CONTEXT\ we try to deal with these issues as well as possible.
641
642\stopsection
643
644\startsection[title={Scaling and shifting}]
645
646\index{scaling}
647\index{shifting}
648
649When we draw a shape, \METAPOST\ will adapt the bounding box accordingly. This
650means that a graphic has its natural dimensions, unless of course we adapt the
651bounding box manually. When you limit your graphic to a simple shape, say a
652rectangle, shifting it to some place can get obscured by this fact. Therefore,
653the following series of shapes appear to be the same.
654
655\startbuffer
656draw
657 unitsquare xscaled 6cm yscaled 1.5cm
658 withpen pencircle scaled 2mm withcolor .625red ;
659\stopbuffer
660
661\typebuffer
662
663\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
664
665\startbuffer
666draw
667 unitsquare shifted (.5,.5) xscaled 6cm yscaled 1.5cm
668 withpen pencircle scaled 2mm withcolor .625red ;
669\stopbuffer
670
671\typebuffer
672
673\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
674
675\startbuffer
676draw
677 unitsquare shifted (.5,.5) xscaled 6cm yscaled 1.5cm
678 withpen pencircle scaled 2mm withcolor .625red ;
679\stopbuffer
680
681\typebuffer
682
683\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
684
685\startbuffer
686draw
687 unitsquare xscaled 6cm yscaled 1.5cm shifted (1cm,1cm)
688 withpen pencircle scaled 2mm withcolor .625red ;
689\stopbuffer
690
691\typebuffer
692
693\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
694
695\startbuffer
696draw
697 unitsquare xscaled 6cm yscaled 1.5cm shifted (1.5cm,1cm)
698 withpen pencircle scaled 2mm withcolor .625red ;
699\stopbuffer
700
701\typebuffer
702
703\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
704
705However, when we combine such graphics into one, we will see in what respect the
706scaling and shifting actually takes place.
707
708\startbuffer
709draw
710 unitsquare xscaled 6cm yscaled 2cm
711 withpen pencircle scaled 3.0mm withcolor .625yellow ;
712draw
713 unitsquare shifted (.5,.5) xscaled 6cm yscaled 2cm
714 withpen pencircle scaled 3.0mm withcolor .625red ;
715draw
716 unitsquare xscaled 6cm yscaled 2cm shifted (1cm,1cm)
717 withpen pencircle scaled 3.0mm withcolor .625white ;
718draw
719 unitsquare xscaled 6cm yscaled 2cm shifted (1.5cm,1cm)
720 withpen pencircle scaled 1.5mm withcolor white ;
721draw
722 unitsquare shifted (.5,.5) xscaled 6cm yscaled 2cm
723 withpen pencircle scaled 1mm withcolor black ;
724draw origin withpen pencircle scaled 1mm ;
725\stopbuffer
726
727\typebuffer
728
729\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
730
731As you can see, the transformations are applied in series. Sometimes this is not
732what we want, in which case we can use parentheses to force the desired
733behaviour. The lesson learned is that {\em scaling and shifting} is not always
734the same as {\em shifting and scaling}.
735
736\startbuffer
737draw
738 origin origin shifted ((4cm,0cm) shifted (4cm,0cm))
739 withpen pencircle scaled 1cm withcolor .625white ;
740draw
741 origin origin shifted (4cm,0cm) shifted (4cm,0cm)
742 withpen pencircle scaled 8mm withcolor .625yellow ;
743draw
744 (origin origin shifted (4cm,0cm)) shifted (4cm,0cm)
745 withpen pencircle scaled 6mm withcolor .625red ;
746draw
747 origin (origin shifted (4cm,0cm) shifted (4cm,0cm))
748 withpen pencircle scaled 4mm withcolor white ;
749\stopbuffer
750
751\typebuffer
752
753\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
754
755Especially when a path results from a call to a macro, using parentheses around a
756path may help, as in the following example.
757
758\startbuffer
759def unitslant = origin origin shifted (1,1) enddef ;
760draw
761 unitslant xscaled 5cm yscaled 1cm
762 withpen pencircle scaled 1cm withcolor .625red ;
763draw
764 (unitslant) xscaled 5cm yscaled 1cm
765 withpen pencircle scaled 5mm withcolor .625yellow ;
766\stopbuffer
767
768\typebuffer
769
770\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
771
772The next definition of \type {unitslant} is therefore better.
773
774\startbuffer
775def unitslant = (origin origin shifted (1,1)) enddef ;
776draw
777 unitslant xscaled 5cm yscaled 1cm
778 withpen pencircle scaled 5mm withcolor .625red ;
779\stopbuffer
780
781\typebuffer
782
783\startlinecorrection[blank]\processMPbuffer\stoplinecorrection
784
785An even better alternative is:
786
787\startbuffer
788path unitslant ; unitslant = origin origin shifted (1,1) ;
789draw
790 unitslant xscaled 5cm yscaled 1cm
791 withpen pencircle scaled 5mm withcolor .625yellow ;
792\stopbuffer
793
794\typebuffer
795
796\startlinecorrection[blank]
797\processMPbuffer
798\stoplinecorrection
799
800\stopsection
801
802\startsection[title={Curve construction}]
803
804\index{curves}
805
806\doifmodeelse{screen}
807 {\def\Xcom{3}\def\Ycom{2}\def\Zcom{\the\textheight}}
808 {\def\Xcom{2}\def\Ycom{3}\def\Zcom{\the\textwidth }}
809
810Chapter 3 of the \METAFONT\ book explains the mathematics behind the construction
811of curves. Both \METAFONT\ and \METAPOST\ implement Bézier curves. The fact that
812these curves are named after Pierre Bézier obscures the fact that the math behind
813them originates with SergeÄ BernshteÄn.
814
815The points on the curve are determined by the following formula:
816
817\placeformula[]
818\startformula
819z(t) = (1t)3 z1 3 (1t)2 t z2 3 (1t) t2 z3 t3 z4
820\stopformula
821
822Here, the parameter $t$ runs from $[0,1]$. As you can see, we are dealing with
823four points. In practice this means that when we construct a curve from multiple
824points, we act on two points and the two control points in between. So, the
825segment that goes from $z1$ to $z4$ is calculated using these two points and
826the points that \METAFONT\METAPOST\ calls post control point and pre control
827point.
828
829\startbuffer[a]
830vardef dodrawmidpoints (expr a, b, c, d, n, col, m) =
831 save e, f, g, h, i, j ; pair e, f, g, h, i, j ;
832 e := .5[a,b] ; f := .5[b,c] ; g := .5[c,d] ;
833 h := .5[e,f] ; i := .5[f,g] ; j := .5[h,i] ;
834 if m= 0 : drawpoints j elseif
835 m= 1 : draw abcd elseif
836 m= 2 : draw efg elseif
837 m= 3 : draw hi elseif
838 m= 4 : draw aehj elseif
839 m= 5 : draw jigd elseif
840 m=11 : drawpoints abcd elseif
841 m=12 : drawpoints efg elseif
842 m=13 : drawpoints hi elseif
843 m=14 : drawpoints aehj elseif
844 m=15 : drawpoints jigd fi withcolor col ;
845 if n>1 :
846 dodrawmidpoints(a, e, h, j, n1, col, m) ;
847 dodrawmidpoints(j, i, g, d, n1, col, m) ;
848 fi ;
849enddef ;
850
851vardef drawmidpoints (expr p, n, col, m) =
852 save a, b, c, d ; pair a, b, c, d ;
853 for x=0 upto length(p)1 :
854 a := point x of p ; b := postcontrol x of p ;
855 d := point x1 of p ; c := precontrol x1 of p ;
856 dodrawmidpoints(a,b,c,d,n,col,m) ;
857 endfor ;
858enddef ;
859\stopbuffer
860
861\startbuffer[b]
862path p ; p := (4cm,4cm)..(6cm,0cm)..(1cm,2cm) ;
863\stopbuffer
864
865\startbuffer[c]
866drawpath p ;
867drawcontrollines p withcolor .625yellow ;
868drawcontrolpoints p withcolor .625red ;
869drawpoints p withcolor .625red ;
870freelabel(btex $z1$ etex, point 0 of p, center p) ;
871freelabel(btex $z2$ etex, postcontrol 0 of p, center p) ;
872freelabel(btex $z3$ etex, precontrol 1 of p, center p) ;
873freelabel(btex $z4$ etex, point 1 of p, center p) ;
874freelabel(btex $z5$ etex, postcontrol 1 of p, center p) ;
875freelabel(btex $z6$ etex, precontrol 2 of p, center p) ;
876freelabel(btex $z7$ etex, point 2 of p, center p) ;
877\stopbuffer
878
879\startbuffer[x]
880draw boundingbox p enlarged 1cm ;
881setbounds currentpicture to boundingbox p enlarged 1cm ;
882currentpicture := currentpicture xsized (.45*\Zcom) ;
883\stopbuffer
884
885\startlinecorrection[blank]
886\processMPbuffer[a,b,c,x]
887\stoplinecorrection
888
889The previous curve is constructed from the three points $z1$, $z4$ and $z7$.
890The curve is drawn in \METAPOST\ by \type {z1..z4..z7} and is made up out of two
891segments. The first segment is determined by the following points:
892
893\startitemize[packed,n]
894\item point $z1$ of the curve
895\item the postcontrol point $z2$ of $z1$
896\item the precontrol point $z3$ of $z4$
897\item point $z4$ of the curve
898\stopitemize
899
900On the next pages we will see how the whole curve is constructed from these
901quadruples of points. The process comes down to connecting the mid points of the
902straight lines to the points mentioned. We do this three times, which is why
903these curves are classified as third order approximations.
904
905The first series of graphics demonstrates the process of determining the mid
906points. The third order midpoint is positioned on the final curve. The second
907series focuses on the results: new sets of four points that will be used in a
908next stage. The last series only shows the third order midpoints. As you can see,
909after some six iterations we have already reached a rather good fit of the final
910curve. The exact number of iterations depends on the resolution needed. You will
911notice that the construction speed (density) differs per segment.
912
913\startpostponing
914
915
916
917\startbuffer[cc]
918drawpath p ; drawpoints p ; drawcontrolpoints p ;
919\stopbuffer
920
921\startbuffer[dd]
922drawmidpoints(p,1,.625red, 11) ; drawmidpoints(p,1,.625yellow, 1) ;
923\stopbuffer
924
925\startbuffer[ee]
926drawmidpoints(p,1,.625red, 12) ; drawmidpoints(p,1,.625yellow, 2) ;
927\stopbuffer
928
929\startbuffer[ff]
930drawmidpoints(p,1,.625red, 13) ; drawmidpoints(p,1,.625yellow, 3) ;
931\stopbuffer
932
933\startbuffer[gg]
934drawmidpoints(p,1,.625red, 14) ; drawmidpoints(p,1,.625yellow, 4) ;
935\stopbuffer
936
937\startbuffer[hh]
938drawmidpoints(p,1,.625red, 15) ; drawmidpoints(p,1,.625yellow, 5) ;
939\stopbuffer
940
941\startbuffer
942\startcombination[\Xcom*\Ycom]
943 {\processMPbuffer[a,b,cc,x]} {points}
944 {\processMPbuffer[a,b,cc,dd,x]} {first order curve}
945 {\processMPbuffer[a,b,cc,dd,ee,x]} {second order curve}
946 {\processMPbuffer[a,b,cc,dd,ee,ff,x]} {third order curve}
947 {\processMPbuffer[a,b,cc,dd,ee,gg,x]} {left side curves}
948 {\processMPbuffer[a,b,cc,dd,ee,hh,x]} {right side curves}
949\stopcombination
950\stopbuffer
951
952\getbuffer \page
953
954\startbuffer[dd]
955drawmidpoints(p,1,.625red, 11) ;
956drawmidpoints(p,1,.625yellow, 1) ;
957\stopbuffer
958
959\startbuffer[ee]
960for i=11, 12 : drawmidpoints(p,1,.625red, i) ; endfor ;
961drawmidpoints(p,1,.625yellow, 2) ;
962\stopbuffer
963
964\startbuffer[ff]
965for i=11, 12, 13 : drawmidpoints(p,1,.625red, i) ; endfor ;
966drawmidpoints(p,1,.625yellow, 3) ;
967\stopbuffer
968
969\startbuffer[gg]
970for i=11,12,13,14 : drawmidpoints(p,1,.625red, i) ; endfor ;
971drawmidpoints(p,1,.625yellow, 4) ;
972\stopbuffer
973
974\startbuffer[hh]
975for i=11, 12, 13, 14, 15 : drawmidpoints(p,1,.625red, i) ; endfor ;
976drawmidpoints(p,1,.625yellow, 5) ;
977\stopbuffer
978
979\startbuffer
980\startcombination[\Xcom*\Ycom]
981 {\processMPbuffer[a,b,cc,x]} {points}
982 {\processMPbuffer[a,b,cc,dd,x]} {first order points}
983 {\processMPbuffer[a,b,cc,ee,x]} {second order points}
984 {\processMPbuffer[a,b,cc,ff,x]} {third order points}
985 {\processMPbuffer[a,b,cc,gg,x]} {left side points}
986 {\processMPbuffer[a,b,cc,hh,x]} {right side points}
987\stopcombination
988\stopbuffer
989
990\getbuffer \page
991
992\startbuffer[cc]
993drawpath p ; drawmidpoints (p,1,.625yellow, 0) ;
994\stopbuffer
995
996\startbuffer[dd]
997drawpath p ; drawmidpoints (p,2,.625yellow, 0) ;
998\stopbuffer
999
1000\startbuffer[ee]
1001drawpath p ; drawmidpoints (p,3,.625yellow, 0) ;
1002\stopbuffer
1003
1004\startbuffer[ff]
1005drawpath p ; drawmidpoints (p,4,.625yellow, 0) ;
1006\stopbuffer
1007
1008\startbuffer[gg]
1009drawpath p ; drawmidpoints (p,5,.625yellow, 0) ;
1010\stopbuffer
1011
1012\startbuffer[hh]
1013drawpath p ; drawmidpoints (p,6,.625yellow, 0) ;
1014\stopbuffer
1015
1016\startbuffer
1017\startcombination[\Xcom*\Ycom]
1018 {\processMPbuffer[a,b,cc,x]} {first iteration}
1019 {\processMPbuffer[a,b,cc,dd,x]} {second iteration}
1020 {\processMPbuffer[a,b,cc,dd,ee,x]} {third iteration}
1021 {\processMPbuffer[a,b,cc,dd,ee,ff,x]} {fourth iteration}
1022 {\processMPbuffer[a,b,cc,dd,ee,ff,gg,x]} {fifth iteration}
1023 {\processMPbuffer[a,b,cc,dd,ee,ff,gg,hh,x]} {sixths iteration}
1024\stopcombination
1025\stopbuffer
1026
1027\getbuffer \page
1028
1029\stoppostponing
1030
1031
1032
1033
1034
1035The path in these examples is defined as follows:
1036
1037\typebuffer[b]
1038
1039If you are playing with graphics like this, the \METAFUN\ macro \type {randomize}
1040may come in handy:
1041
1042\startbuffer[bb]
1043p := p randomized (1cm,.5cm) ;
1044\stopbuffer
1045
1046\typebuffer[bb]
1047
1048If we apply this operation a couple of times we can see how the (control) points
1049vary. (Using the randomizer saves us the troubles of finding nice example
1050values.) The angle between the tangent as well as the distance from the parent
1051point determine the curve.
1052
1053\startbuffer[xx]
1054currentpicture := currentpicture scaled .5 ;
1055\stopbuffer
1056
1057\startlinecorrection[blank]
1058\hbox to \hsize
1059 {\processMPbuffer[a,b,bb,c,x,xx]\hss
1060 \processMPbuffer[a,b,bb,c,x,xx]\hss
1061 \processMPbuffer[a,b,bb,c,x,xx]\hss
1062 \processMPbuffer[a,b,bb,c,x,xx]}
1063\stoplinecorrection
1064
1065
1066
1067Just in case you are interested in how such graphical simulations can be
1068organized, we show simplified versions of the macros used here. (In the previous
1069examples we minimized the complexity of the code by using buffers, but describing
1070this mechanism is out of the scope of this section.)
1071
1072\startbuffer[demo]
1073vardef dodrawmidpoints (expr a, b, c, d, n) =
1074 save e, f, g, h, i, j ; pair e, f, g, h, i, j ;
1075 e := .5[a,b] ; f := .5[b,c] ; g := .5[c,d] ;
1076 h := .5[e,f] ; i := .5[f,g] ; j := .5[h,i] ;
1077 draw j ;
1078 if n>1 :
1079 dodrawmidpoints(a, e, h, j, n1) ;
1080 dodrawmidpoints(j, i, g, d, n1) ;
1081 fi ;
1082enddef ;
1083
1084vardef drawmidpoints (expr p, n) =
1085 save a, b, c, d ; pair a, b, c, d ;
1086 for x=0 upto length(p)1 :
1087 a := point x of p ; b := postcontrol x of p ;
1088 d := point x1 of p ; c := precontrol x1 of p ;
1089 dodrawmidpoints(a, b, c, d, n) ;
1090 endfor ;
1091enddef ;
1092\stopbuffer
1093
1094We need to loop over all segments of a curve, where for each segment the left and
1095right side sub curves are handled recursively, upto the requested depth (denoted
1096as \type {n}). For this we define the following macros.
1097
1098\typebuffer[demo]
1099
1100\startbuffer[zero]
1101drawoptions (withpen pencircle scaled 5pt withcolor .625red);
1102\stopbuffer
1103
1104\startbuffer[extra]
1105drawoptions (withpen pencircle scaled 5pt withcolor .625yellow);
1106\stopbuffer
1107
1108We apply this macro to a simple shape:
1109
1110\startbuffer[one]
1111drawmidpoints (fullcircle xscaled 300pt yscaled 50pt, 1) ;
1112\stopbuffer
1113
1114\typebuffer[one]
1115
1116When drawn, this results in the points that makes up the
1117curve:
1118
1119\startlinecorrection[blank]
1120\processMPbuffer[demo,zero,one]
1121\stoplinecorrection
1122
1123We now add an extra iteration (resulting in the yellow points):
1124
1125\startbuffer[two]
1126drawmidpoints (fullcircle xscaled 300pt yscaled 50pt, 2) ;
1127\stopbuffer
1128
1129\typebuffer[two]
1130
1131and get:
1132
1133\startlinecorrection[blank]
1134\processMPbuffer[demo,zero,two,extra,one]
1135\stoplinecorrection
1136
1137We dont even need that much iterations to get a good result. The depth needed to
1138get a good result depends on the size of the pen and the resolution of the device
1139on which the curve is visualized.
1140
1141\startbuffer[zero]
1142drawoptions (withpen pencircle scaled 2pt withcolor .625red) ;
1143\stopbuffer
1144
1145\startbuffer[three]
1146for i=1 upto 7 :
1147 drawmidpoints (fullcircle
1148 xscaled (300pti*10pt) yscaled (50pti*10pt), i) ;
1149endfor ;
1150\stopbuffer
1151
1152\typebuffer[three]
1153
1154Here we show 7 iterations in one graphic.
1155
1156\startlinecorrection[blank]
1157\processMPbuffer[demo,zero,three]
1158\stoplinecorrection
1159
1160In practice it is not that trivial to determine the depth needed. The next
1161example demonstrates how the resolution of the result depends on the length and
1162nature of the segment.
1163
1164\startbuffer[four]
1165drawmidpoints (fullsquare
1166 xscaled 300pt yscaled 50pt randomized (20pt,10pt), 5) ;
1167\stopbuffer
1168
1169\typebuffer[four]
1170
1171\startlinecorrection[blank]
1172\processMPbuffer[demo,zero,four]
1173\stoplinecorrection
1174
1175\stopsection
1176
1177\startsection[title={Inflection, tension and curl}]
1178
1179\index{inflection}
1180\index{tension}
1181\index{curl}
1182
1183The \METAPOST\ manual describes the meaning of \type {...} as \quotation {choose
1184an inflectionfree path between these points unless the endpoint directions make
1185this impossible}. To use the words of David Arnold: a point of inflection is
1186where a path switches concavity, from concave up to concave down, for example.
1187
1188It is surprisingly difficult to find nice examples that demonstrate the
1189difference between \type {..} and \type {...}, as it is often \quote {impossible}
1190to honour the request for less inflection. We will demonstrate this with a few
1191graphics.
1192
1193In the four figures on the next pages, you will see that \type {...} is not
1194really suited for taming wild curves. If you really want to make sure that a
1195curve stays within certain bounds, you have to specify it as such using control
1196or intermediate points. In the figures that follow, the gray curves draw the
1197random path using \type {..} on top of yellow curves that use the \type {...}
1198connection. As you can see, in only a few occasions do the yellow \quote
1199{inflection} free curves show up.
1200
1201For those who asked for the code that produces these pictures, we now include it
1202here. We use a macro \type {sample} which we define as a usable graphic (nearly
1203all examples in this manual are coded in the document source).
1204
1205\startbuffer
1206\startuseMPgraphic{sample}
1207def sample (expr rx, ry) =
1208 path p, q ; numeric n, m, r, a, b ;
1209 color c ; c := \MPcolor{lightgray} ;
1210 a := 3mm ; b := 2mm ; r := 2cm ; n := 7 ; m := 5 ;
1211 q := unitsquare scaled r xyscaled (n,m) shifted (.5r,.5r) ;
1212 draw q withpen pencircle scaled (b4) withcolor .625yellow;
1213 for i=1 upto n : for j=1 upto m :
1214 p := (fullcircle scaled r randomized (rrx,rry))
1215 shifted ((i,j) scaled r) ;
1216 pickup pencircle scaled a ;
1217 draw for k=0 upto length(p) :
1218 point k of p .. endfor cycle withcolor c ;
1219 draw for k=0 upto length(p) :
1220 point k of p ... endfor cycle withcolor c ;
1221 pickup pencircle scaled b ;
1222 draw for k=0 upto length(p) :
1223 point k of p .. endfor cycle withcolor .625yellow ;
1224 draw for k=0 upto length(p) :
1225 point k of p ... endfor cycle withcolor .625white ;
1226 for k=0 upto length(p) :
1227 draw point k of p withcolor .625red ;
1228 endfor ;
1229 endfor ; endfor ;
1230 setbounds currentpicture to q ;
1231enddef ;
1232\stopuseMPgraphic
1233\stopbuffer
1234
1235\typebuffer \getbuffer
1236
1237As you see, not so much code is needed. The graphics themselves were produced
1238with a couple of commands like:
1239
1240\startbuffer
1241\placefigure
1242 {Circles with minimized inflection and 25\% randomized points.}
1243 {\startMPcode
1244 \includeMPgraphic{sample} ; sample(4,4) ;
1245 \stopMPcode}
1246\stopbuffer
1247
1248\typebuffer
1249
1250\startpostponing
1251
1252\placefigure
1253 {Circles with minimized inflection and 25\% randomized points.}
1254 {\startMPcode\includeMPgraphic{sample} ; sample(4,4) ; \stopMPcode}
1255
1256\placefigure
1257 {Circles with minimized inflection and 33\% randomized points.}
1258 {\startMPcode\includeMPgraphic{sample} ; sample(3,3) ; \stopMPcode}
1259
1260\page
1261
1262\placefigure
1263 {Circles with minimized inflection and 50\% randomized points.}
1264 {\startMPcode\includeMPgraphic{sample} ; sample(2,2) ; \stopMPcode}
1265
1266\placefigure
1267 {Circles with minimized inflection and 100\% randomized points.}
1268 {\startMPcode\includeMPgraphic{sample} ; sample(1,1) ; \stopMPcode}
1269
1270\page
1271
1272\stoppostponing
1273
1274The tension specifier can be used to influence the curvature. To quote the
1275\METAPOST\ manual once more: \quotation {The tension parameter can be less than
1276one, but it must be at least $34$}. The following paths are the same:
1277
1278\starttyping
1279z1 .. z2
1280z1 .. tension 1 .. z2
1281z1 .. tension 1 and 1 .. z2
1282\stoptyping
1283
1284The triple dot command \type {...} is actually a macro that makes the following
1285commands equivalent. Both commands will draw identical paths.
1286
1287\starttyping
1288z1 ... z2
1289z1 .. tension atleast 1 .. z2
1290\stoptyping
1291
1292The \type {atleast} directive tells \METAPOST\ to do some magic behind the
1293screens. Both the $34$ and the \type {atleast} lead directly to the question:
1294\quotation {What, exactly, is the influence of the tension directive?} We will
1295try to demystify the \type {tension} specifier through a sequence of graphics.
1296
1297\startbuffer
1298u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1299def sample (expr p, c) =
1300 draw p withpen pencircle scaled 2.5mm withcolor white ;
1301 draw p withpen pencircle scaled 2.0mm withcolor c ;
1302enddef ;
1303for i=.75 step .05 until 1 :
1304 sample (z1 .. tension i .. z2 .. z3, .625red) ;
1305endfor ;
1306for i=1 step .05 until 2 :
1307 sample (z1 .. tension i .. z2 .. z3, .625yellow) ;
1308endfor ;
1309sample (z1 .. z2 .. z3, .625white) ;
1310sample (z1 ... z2 ... z3, .625white) ;
1311\stopbuffer
1312
1313\typebuffer
1314
1315Indeed values less than .75 give an error message, but large values are okay. As
1316you can see, the two gray curves are the same. Here, \type {atleast 1} means1,
1317even if larger values are useful.
1318
1319\startlinecorrection[blank]
1320\processMPbuffer
1321\stoplinecorrection
1322
1323\startbuffer
1324u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1325def sample (expr p, c) =
1326 draw p withpen pencircle scaled 2.5mm withcolor white ;
1327 draw p withpen pencircle scaled 2.0mm withcolor c ;
1328enddef ;
1329for i=.75 step .05 until 1 :
1330 sample (z1 .. tension i and 2i .. z2 .. z3, .625red) ;
1331endfor ;
1332for i=1 step .05 until 2 :
1333 sample (z1 .. tension i and 2i .. z2 .. z3, .625yellow) ;
1334endfor ;
1335sample (z1 .. z2 .. z3, .625white) ;
1336sample (z1 ... z2 ... z3, .625white) ;
1337\stopbuffer
1338
1339Curves finally are made up out of points, and each point has two control points.
1340Since the \type {tension} specifier finally becomes a control point, it is not
1341surprising that you may specify two tension values. If we replace the tension in
1342the previous example by
1343
1344\starttyping
1345.. tension i and 2i ..
1346\stoptyping
1347
1348we get the following graphic:
1349
1350\startlinecorrection[blank]
1351\processMPbuffer
1352\stoplinecorrection
1353
1354\startbuffer
1355u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1356def sample (expr p, c) =
1357 draw p withpen pencircle scaled 2.5mm withcolor white ;
1358 draw p withpen pencircle scaled 2.0mm withcolor c ;
1359enddef ;
1360for i=.75 step .05 until 1 :
1361 sample (z1 .. tension 2i and i .. z2 .. z3, .625red) ;
1362endfor ;
1363for i=1 step .05 until 2 :
1364 sample (z1 .. tension 2i and i .. z2 .. z3, .625yellow) ;
1365endfor ;
1366sample (z1 .. z2 .. z3, .625white) ;
1367sample (z1 ... z2 ... z3, .625white) ;
1368\stopbuffer
1369
1370If we swap both values (\type {.. tension 2i and i ..}) we get:
1371
1372\startlinecorrection[blank]
1373\processMPbuffer
1374\stoplinecorrection
1375
1376\startbuffer[a]
1377u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1378def sample (expr p, c) =
1379 drawpath p withpen pencircle scaled 2.5mm withcolor c ;
1380 drawcontrollines p withcolor c ;
1381 drawpoints p ;
1382 drawcontrolpoints p ;
1383enddef ;
1384\stopbuffer
1385
1386We mentioned control points. We will now draw a few extreme tensions and show the
1387control points as \METAPOST\ calculates them.
1388
1389\startbuffer[b]
1390sample (z1 .. tension 0.75 .. z2 .. z3, .625red) ;
1391sample (z1 .. tension 2.00 .. z2 .. z3, .625yellow) ;
1392sample (z1 .. z2 .. z3, .625white) ;
1393\stopbuffer
1394
1395\typebuffer[b]
1396
1397First we will show the symmetrical tensions.
1398
1399\startlinecorrection[blank]
1400\processMPbuffer[a,b]
1401\stoplinecorrection
1402
1403The asymetrical tensions are less prominent. We use the following values:
1404
1405\startbuffer[b]
1406sample (z1 .. tension .75 and 10 .. z2 .. z3, .625red) ;
1407sample (z1 .. tension 10 and .75 .. z2 .. z3, .625yellow) ;
1408sample (z1 .. z2 .. z3, .625white) ;
1409\stopbuffer
1410
1411\typebuffer[b]
1412
1413\startlinecorrection[blank]
1414\processMPbuffer[a,b]
1415\stoplinecorrection
1416
1417What happens when you use the \METAPOST\ maximum value of \type {infinity}
1418instead of 10? Playing with this kind of graphic can be fun, especially when we
1419apply a few tricks.
1420
1421\startbuffer
1422def sample (expr p, c) =
1423 draw p withpen pencircle scaled 2.5mm withcolor white ;
1424 draw p withpen pencircle scaled 2.0mm withcolor c ;
1425enddef;
1426
1427u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1428
1429for i=0 step .05 until 1 :
1430 sample(z1 .. tension (.75i) .. z2 .. z3, i[.625red,.625yellow]) ;
1431endfor;
1432\stopbuffer
1433
1434\typebuffer
1435
1436Here we change the color along with the tension. This clearly demonstrates that
1437were dealing with a non linear phenomena.
1438
1439\startlinecorrection[blank]
1440\processMPbuffer
1441\stoplinecorrection
1442
1443We can (misuse) transparant colors to illustrate how the effect becomes less with
1444growing tension.
1445
1446\startbuffer
1447def sample (expr p) (text c)=
1448 draw p withpen pencircle scaled 2.0mm withcolor c ;
1449enddef;
1450
1451u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1452
1453for i=0 step .05 until 1 :
1454 sample(z1 .. tension (.75i) .. z2 .. z3, transparent(1,1i,.625red)) ;
1455endfor;
1456\stopbuffer
1457
1458\typebuffer
1459
1460\startlinecorrection[blank]
1461\processMPbuffer
1462\stoplinecorrection
1463
1464A third magic directive is \type {curl}. The curl is attached to a point between
1465\type {{ }}, like \type {{curl 2}}. Anything between curly braces is a direction
1466specifier, so instead of a \type {curl} you may specify a vector, like \type
1467{{(2,3)}}, a pair of numbers, as in \type {{2,3}}, or a direction, like \type
1468{{dir 30}}. Because vectors and angles are straightforward, we will focus a bit
1469on \type {curl}.
1470
1471\starttyping
1472z0 .. z1 .. z2
1473z0 {curl 1} .. z1 .. {curl 1} z2
1474\stoptyping
1475
1476So, a \type {curl} of1 is the default. When set to1, the begin andor end
1477points are approached. Given the following definitions:
1478
1479\startbuffer[a]
1480u := 1cm ; z1 = (0,0) ; z2 = (2u,4u) ; z3 = (4u,0) ;
1481def sample (expr p, c) =
1482 draw p withpen pencircle scaled 2.5mm withcolor white ;
1483 draw p withpen pencircle scaled 2.0mm withcolor c ;
1484enddef ;
1485\stopbuffer
1486
1487\typebuffer[a]
1488
1489We can draw three curved paths.
1490
1491\startbuffer[b]
1492sample (z1 {curl 0} .. z2 .. {curl 0} z3, .625red) ;
1493sample (z1 {curl 2} .. z2 .. {curl 2} z3, .625yellow) ;
1494sample (z1 {curl 1} .. z2 .. {curl 1} z3, .625white) ;
1495\stopbuffer
1496
1497\typebuffer[b]
1498
1499The third (gray) curve is the default situation, so we could have left the \type
1500{curl} specifier out of the expression.
1501
1502\startlinecorrection[blank]
1503\processMPbuffer[a,b]
1504\stoplinecorrection
1505
1506\startbuffer[b]
1507sample (z1 {curl 0} .. z2 .. {curl 0} z3, .625red) ;
1508sample (z1 {curl infinity} .. z2 .. {curl infinity} z3, .625yellow) ;
1509sample (z1 {curl 1} .. z2 .. {curl 1} z3, .625white) ;
1510\stopbuffer
1511
1512The curly specs have a lower bound of zero and no upper bound. When we use
1513\METAPOST\ maximum value of \type {infinity} instead of2, we get:
1514
1515\startlinecorrection[blank]
1516\processMPbuffer[a,b]
1517\stoplinecorrection
1518
1519These curves were defined as:
1520
1521\typebuffer[b]
1522
1523It may sound strange, but internally \METAPOST\ can handle
1524larger values than \type {infinity}.
1525
1526\startbuffer[b]
1527sample (z1 {curl infinity} .. z2 .. {curl infinity} z3, .625red) ;
1528sample (z1 {curl 4infinity} .. z2 .. {curl 4infinity} z3, .625yellow) ;
1529sample (z1 {curl 8infinity} .. z2 .. {curl 8infinity} z3, .625white) ;
1530\stopbuffer
1531
1532\typebuffer[b]
1533
1534Although this is quite certainly undefined behaviour, interesting effects can be
1535achieved. When you turn off \METAPOSTs first stage overflow catcher by setting
1536\type {warningcheck} to zero, you can go upto 8 times \type {infinity}, which,
1537being some $2{15}$, is still far from what todays infinity is supposed to be.
1538
1539\startlinecorrection[blank]
1540\processMPbuffer[a,b]
1541\stoplinecorrection
1542
1543As the builtin \METAPOST\ command \type {..} accepts the \type {curl} and \type
1544{tension} directives as described in this section, you will now probably
1545understand the following plain \METAPOST\ definitions:
1546
1547\starttyping
1548def = {curl 1} .. {curl 1} enddef ;
1549def = .. tension infinity .. enddef ;
1550def ... = .. tension atleast 1 .. enddef ;
1551\stoptyping
1552
1553These definitions also point out why you cannot add directives to the left or
1554right side of \type {}, \type {} and \type {...}: they are directives
1555themselves!
1556
1557\stopsection
1558
1559\startsection[title={Transformations}]
1560
1561\index{transformations}
1562
1563A \type {transform} is a vector that is used in what is called an affine
1564transformation. To quote the \METAPOST\ manual:
1565
1566\startquotation
1567If $p=(px,py)$ is a pair and $T$ is a transform, then
1568\type {p transform T} is a pair of the form:
1569
1570\startformula
1571(tx t{xx} px t{xy} py, ty t{yx} px t{yy} py)
1572\stopformula
1573
1574where the six numeric quantities $(tx, ty, t{xx}, t{xy},
1575t{yx}, t{yy})$ determine T.
1576\stopquotation
1577
1578In literature concerning \POSTSCRIPT\ and \PDF\ you will find many references to
1579such transformation matrices. A matrix of $(sx,0,0,sy,0,0)$ is scaling by $sx$
1580in the horizontal direction and $sy$ in the vertical direction, while
1581$(1,0,tx,1,0,ty)$ is a shift over $tx,ty$. Of course combinations are also
1582possible.
1583
1584Although these descriptions seem in conflict with each other in the nature and
1585order of the transform components in the vectors, the concepts are the same. You
1586normally populate transformation matrices using \type {scaled}, \type {shifted},
1587\type {rotated}.
1588
1589\starttyping
1590transform t ; t := identity shifted (a,b) rotated c scaled d ;
1591path p ; p := fullcircle transformed t ;
1592\stoptyping
1593
1594The previous lines of code are equivalent to:
1595
1596\starttyping
1597path p ; p := fullcircle shifted (a,b) rotated c scaled d ;
1598\stoptyping
1599
1600You always need a starting point, in this case the identity matrix \type
1601{identity}: $(0,0,1,0,0,1)$. By the way, in \POSTSCRIPT\ the zero vector is
1602$(1,0,0,1,0,0)$. So, unless you want to extract the components using \type
1603{xpart}, \type {xypart}, \type {xxpart}, \type {ypart}, \type {yxpart} andor \
1604\type {yypart}, you may as well forget about the internal representation.
1605
1606You can invert a transformation using the \type {inverse} macro, which is defined
1607as follows, using an equation:
1608
1609\starttyping
1610vardef inverse primary T =
1611 transform T ; T transformed T = identity ; T
1612enddef ;
1613\stoptyping
1614
1615Using transform matrices makes sense when similar transformations need to be
1616applied on many paths, pictures, pens, or other transforms. However, in most
1617cases you will use the predefined commands \type {scaled}, \type {shifted}, \type
1618{rotated} and alike. We will now demonstrate the most common transformations in a
1619text example.
1620
1621\startbuffer[a]
1622draw btex \bfd MetaFun etex ;
1623draw boundingbox currentpicture withcolor .625yellow ;
1624\stopbuffer
1625
1626\typebuffer[a]
1627
1628Before an independent \METAPOST\ run, the \typ {btex ... etex}s are filtered
1629from the file and passed on to \TEX. After that, the \DVI\ file is converted to a
1630list of pictures, which is consulted by \METAPOST. This is no longer the case in
1631\LUATEX\ where we use \MPLIB, so users dont have to worry about these issues:
1632just ignore what is mentioned in the official \METAPOST\ manual.
1633
1634We can manipulate the pictures representing text like any graphic as well as draw
1635it with \type {draw}.
1636
1637\startlinecorrection[blank]
1638\processMPbuffer[a]
1639\stoplinecorrection
1640
1641We show the transformations in relation to the origin and make the origin stand
1642out a bit more by painting it a bit larger in white first.
1643
1644\startbuffer[c]
1645draw origin withpen pencircle scaled 1.5mm withcolor white ;
1646draw origin withpen pencircle scaled 1mm withcolor .625red
1647\stopbuffer
1648
1649\typebuffer[c]
1650
1651The origin is in the lower left corner of the picture.
1652
1653\startlinecorrection[blank]
1654\processMPbuffer[a,c]
1655\stoplinecorrection
1656
1657Because the transformation keywords are proper english, we let the pictures speak
1658for themselves.
1659
1660
1661
1662\startbuffer[b]
1663currentpicture := currentpicture shifted (0,1cm) ;
1664\stopbuffer
1665
1666\page[preference] \typebuffer[b] \page[no]
1667
1668\startlinecorrection[blank]
1669\processMPbuffer[a,b,c]
1670\stoplinecorrection
1671
1672
1673
1674\startbuffer[b]
1675currentpicture := currentpicture rotated 180 ;
1676\stopbuffer
1677
1678\page[preference] \typebuffer[b] \page[no]
1679
1680\startlinecorrection[blank]
1681\processMPbuffer[a,b,c]
1682\stoplinecorrection
1683
1684
1685
1686\startbuffer[b]
1687currentpicture := currentpicture rotatedaround(origin,30) ;
1688\stopbuffer
1689
1690\page[preference] \typebuffer[b] \page[no]
1691
1692\startlinecorrection[blank]
1693\processMPbuffer[a,b,c]
1694\stoplinecorrection
1695
1696
1697
1698\startbuffer[b]
1699currentpicture := currentpicture scaled 1.75 ;
1700\stopbuffer
1701
1702\page[preference] \typebuffer[b] \page[no]
1703
1704\startlinecorrection[blank]
1705\processMPbuffer[a,b,c]
1706\stoplinecorrection
1707
1708
1709
1710\startbuffer[b]
1711currentpicture := currentpicture scaled 1 ;
1712\stopbuffer
1713
1714\page[preference] \typebuffer[b] \page[no]
1715
1716\startlinecorrection[blank]
1717\processMPbuffer[a,b,c]
1718\stoplinecorrection
1719
1720
1721
1722\startbuffer[b]
1723currentpicture := currentpicture xscaled 3.50 ;
1724\stopbuffer
1725
1726\page[preference] \typebuffer[b] \page[no]
1727
1728\startlinecorrection[blank]
1729\processMPbuffer[a,b,c]
1730\stoplinecorrection
1731
1732
1733
1734\startbuffer[b]
1735currentpicture := currentpicture xscaled 1 ;
1736\stopbuffer
1737
1738\page[preference] \typebuffer[b] \page[no]
1739
1740\startlinecorrection[blank]
1741\processMPbuffer[a,b,c]
1742\stoplinecorrection
1743
1744
1745
1746\startbuffer[b]
1747currentpicture := currentpicture yscaled .5 ;
1748\stopbuffer
1749
1750\page[preference] \typebuffer[b] \page[no]
1751
1752\startlinecorrection[blank]
1753\processMPbuffer[a,b,c]
1754\stoplinecorrection
1755
1756
1757
1758\startbuffer[b]
1759currentpicture := currentpicture yscaled 1 ;
1760\stopbuffer
1761
1762\page[preference] \typebuffer[b] \page[no]
1763
1764\startlinecorrection[blank]
1765\processMPbuffer[a,b,c]
1766\stoplinecorrection
1767
1768
1769
1770\startbuffer[b]
1771currentpicture := currentpicture slanted .5 ;
1772\stopbuffer
1773
1774\page[preference] \typebuffer[b] \page[no]
1775
1776\startlinecorrection[blank]
1777\processMPbuffer[a,b,c]
1778\stoplinecorrection
1779
1780
1781
1782\startbuffer[b]
1783currentpicture := currentpicture slanted .5 ;
1784\stopbuffer
1785
1786\page[preference] \typebuffer[b] \page[no]
1787
1788\startlinecorrection[blank]
1789\processMPbuffer[a,b,c]
1790\stoplinecorrection
1791
1792
1793
1794\startbuffer[b]
1795currentpicture := currentpicture zscaled (.75,.25) ;
1796\stopbuffer
1797
1798\page[preference] \typebuffer[b] \page[no]
1799
1800\startlinecorrection[blank]
1801\processMPbuffer[a,b,c]
1802\stoplinecorrection
1803
1804
1805
1806\startbuffer[b]
1807currentpicture := currentpicture
1808 reflectedabout(llcorner currentpicture,urcorner currentpicture) ;
1809\stopbuffer
1810
1811\page[preference] \typebuffer[b] \page[no]
1812
1813\startlinecorrection[blank]
1814\processMPbuffer[a,b,c]
1815\stoplinecorrection
1816
1817
1818
1819A path has a certain direction. When the \type {turningnumber} of a path is
1820larger than zero, it runs in clockwise direction. The \METAPOST\ primitive \type
1821{reverse} changes the direction, while the macro \type {counterclockwise} can be
1822used to get a path running in a well defined direction.
1823
1824\startbuffer
1825drawoptions(withpen pencircle scaled 2pt withcolor .625red) ;
1826path p ; p := fullcircle scaled 1cm ;
1827drawarrow p ;
1828drawarrow reverse p shifted (2cm,0) ;
1829drawarrow counterclockwise p shifted (4cm,0) ;
1830drawarrow counterclockwise reverse p shifted (6cm,0) ;
1831drawarrow reverse counterclockwise p shifted (8cm,0) ;
1832\stopbuffer
1833
1834\typebuffer
1835
1836\startlinecorrection[blank]
1837\processMPbuffer
1838\stoplinecorrection
1839
1840\stopsection
1841
1842\startsection[title={Only this far}]
1843
1844When you take a close look at the definitions of the Computer Modern Roman fonts,
1845defined in the \METAFONT\ book, you will notice a high level of abstraction.
1846Instead of hard coded points you will find points defined in terms of \quote
1847{being the same as this point} or \quote {touching that point}. In this section
1848we will spend some time on this touchy aspect.
1849
1850\startbuffer[a]
1851pickup pencircle scaled 2mm ;
1852path p ; p := fullsquare scaled 2cm ;
1853draw p withcolor .625white ;
1854\stopbuffer
1855
1856\startlinecorrection[blank]
1857\processMPbuffer[a]
1858\stoplinecorrection
1859
1860This rectangle is a scaled instance of the predefined \METAFUN\ path \type
1861{fullsquare} which is centered around the origin.
1862
1863\typebuffer[a]
1864
1865On this path, halfway between two of its corners, we define a point \type {q}:
1866
1867\startbuffer[b]
1868pair q ; q := .5[llcorner p, lrcorner p] ;
1869\stopbuffer
1870
1871\typebuffer[b]
1872
1873We draw this point in red, using:
1874
1875\startbuffer[c]
1876draw q withcolor .625red ;
1877\stopbuffer
1878
1879\typebuffer[c]
1880
1881As you can see, this point is drawn on top of the path.
1882
1883\startlinecorrection[blank]
1884\processMPbuffer[a,b,c]
1885\stoplinecorrection
1886
1887There are four of those midpoints, and when we connect them, we get:
1888
1889\startbuffer[c]
1890draw q q rotated 90 q rotated 180
1891 q rotated 270 cycle withcolor .625red ;
1892\stopbuffer
1893
1894\startlinecorrection[blank]
1895\processMPbuffer[a,b,c]
1896\stoplinecorrection
1897
1898Because path \type {p} is centered around the origin, we can simply rotate point
1899\type {q} a few times.
1900
1901\typebuffer[c]
1902
1903There are situations, where you dont want the red path to be drawn inside
1904another path, or more general: where you want points to touch instead of being
1905overlayed.
1906
1907\startlinecorrection[blank]
1908\processMPbuffer[a,b,c]
1909\stoplinecorrection
1910
1911We can achieve this by defining point \type {q} to be located on top of the
1912midpoint.
1913
1914\startbuffer[b]
1915pair q ; q := top .5[llcorner p, lrcorner p] ;
1916\stopbuffer
1917
1918\typebuffer[b]
1919
1920The predefined macro \type {top} moves the point over the distance similar to the
1921current pen width.
1922
1923\startlinecorrection[blank]
1924\processMPbuffer[a,b,c]
1925\stoplinecorrection
1926
1927Because we are dealing with two drawing operations, and since the path inside is
1928drawn through the center of points, we need to repeat this move in order to draw
1929the red path really inside the other one.
1930
1931\startbuffer[b]
1932pair q ; q := top top .5[llcorner p, lrcorner p] ;
1933\stopbuffer
1934
1935\typebuffer[b]
1936
1937Operations like \type {top} and its relatives \type {bot}, \type {lft} and \type
1938{rt} can be applied sequentally.
1939
1940\startlinecorrection[blank]
1941\processMPbuffer[a,b,c]
1942\stoplinecorrection
1943
1944We already showed that \type {q} was defined as a series of rotations.
1945
1946\typebuffer[c]
1947
1948As an intermezzo we will show an alternative definition of \type {q}. Because
1949each point is rotated 90 degrees more, we can define a macro that expands into
1950the point and rotates afterwards. Because each consecutive point on the path is
1951rotated an additional 90 degrees, we use the \METAPOST\ macro \type {hide} to
1952isolate the assignment. The \type {hide} command executes the hidden command and
1953afterwards continues as if it were never there. You must not confuse this with
1954grouping, since the hidden commands are visible to their surroundings.
1955
1956\startbuffer[c]
1957def qq = q hide(q := q rotated 90) enddef ;
1958draw qq qq qq qq cycle withcolor .625red ;
1959\stopbuffer
1960
1961\typebuffer[c]
1962
1963The macro \type {top} uses the characteristics of the current pen to determine
1964the displacement. However, for the more complicated pen shapes we need a
1965different trick to get an inside path. Lets start by defining an elliptical
1966path.
1967
1968\startbuffer[a]
1969pickup pencircle xscaled 3mm yscaled 5mm rotated 30 ;
1970path p ; p := fullcircle xscaled 6cm yscaled 3cm ;
1971draw p withcolor .625white ;
1972\stopbuffer
1973
1974\typebuffer[a]
1975
1976We draw this path using a non standard pen. In the \METAFONT\ manual you will
1977find methods to draw shapes with similar pens, where the pen is also turning, as
1978it does in real calligraphy. Here we stick to a more simple one.
1979
1980\startlinecorrection[blank]
1981\processMPbuffer[a]
1982\stoplinecorrection
1983
1984We construct the inner path from the points that make up the curve. Watch how we
1985use a for loop to compose the new path. When used this way, no semi colon may be
1986used to end the loop, since it would isolate the color directive.
1987
1988\startbuffer[b]
1989draw point 0 of p
1990 for i=1 upto length(p) : point (i) of p endfor
1991 withcolor .625red ;
1992\stopbuffer
1993
1994\typebuffer[b]
1995
1996The points are still located on the original path.
1997
1998\startlinecorrection[blank]
1999\processMPbuffer[a,b]
2000\stoplinecorrection
2001
2002We can move the points to the inside by shifting them over the penwidth in the
2003direction perpendicular to the point. Because we use this transformation more
2004than once, we wrap it into a macro. This also keeps the code readable.
2005
2006\startbuffer[b]
2007vardef inside expr pnt of p =
2008 (point pnt of p shifted
2009 (penoffset direction pnt of p of currentpen))
2010enddef ;
2011draw inside 0 of p
2012 for i=1 upto length(p) : inside i of p endfor
2013 withcolor .625red ;
2014\stopbuffer
2015
2016\typebuffer[b]
2017
2018Whenever you define a pen, \METAPOST\ stores its characteristics in some private
2019variables which are used in the \type {top} and alike directives. The \type
2020{penoffset} is a built in primitive and is defined as the \quotation {point on
2021the pen furthest to the right of the given direction}. Deep down in \METAPOST\
2022pens are actually simple paths and therefore \METAPOST\ has a notion of a point
2023on the penpath. In the \METAFONT\ book and \METAPOST\ manual you can find in
2024depth discussions on pens.
2025
2026\startlinecorrection[blank]
2027\processMPbuffer[a,b]
2028\stoplinecorrection
2029
2030Were still not there. Like in a previous example, we need to shift over twice
2031the pen width. To get good results, we should determine the width of the pen at
2032that particular point, which is not trivial. The more general solution, which
2033permits us to specify the amount of shifting, is as follows.
2034
2035\startbuffer[b]
2036vardef penpoint expr pnt of p =
2037 save n, d ; numeric n, d ;
2038 (n,d) = if pair pnt : pnt else : (pnt,1) fi ;
2039 (point n of p shifted
2040 ((penoffset direction n of p of currentpen) scaled d))
2041enddef ;
2042\stopbuffer
2043
2044\typebuffer[b]
2045
2046When the point specification is extended with a distance, in which case we have a
2047pair expression, the point and distance are derived from this specification.
2048First we demonstrate the simple case:
2049
2050\startbuffer[c]
2051draw penpoint 0 of p
2052 for i=1 upto length(p)1 : .. penpoint i of p endfor .. cycle
2053 withcolor .625red ;
2054\stopbuffer
2055
2056\typebuffer[c]
2057
2058\startlinecorrection[blank]
2059\processMPbuffer[a,b,c]
2060\stoplinecorrection
2061
2062In the next graphic, we draw both an inner and and outer path.
2063
2064\startbuffer[c]
2065draw penpoint (0,2) of p
2066 for i=1 upto length(p)1 : .. penpoint (i,2) of p endfor .. cycle
2067 withcolor .625red ;
2068draw penpoint (0,2) of p
2069 for i=1 upto length(p)1 : .. penpoint (i,2) of p endfor .. cycle
2070 withcolor .625yellow ;
2071\stopbuffer
2072
2073\typebuffer[c]
2074
2075\startlinecorrection[blank]
2076\processMPbuffer[a,b,c]
2077\stoplinecorrection
2078
2079\startbuffer[a]
2080path p, q, r ;
2081
2082p := fullcircle scaled 3cm ;
2083q := p shifted (7cm,0cm) ;
2084r := center p center q ;
2085\stopbuffer
2086
2087\startbuffer[b]
2088pair pr, qr ;
2089
2090pr := p intersectionpoint r ;
2091qr := q intersectionpoint r ;
2092
2093r := r cutbefore pr cutafter qr ;
2094\stopbuffer
2095
2096\startbuffer[c]
2097r := r cutbefore (point 5pt on r) ;
2098r := r cutafter (point 5pt on r) ;
2099\stopbuffer
2100
2101\startbuffer[cc]
2102r := r cutends 5pt ;
2103\stopbuffer
2104
2105\startbuffer[d]
2106draw p withpen pencircle scaled 10pt withcolor .625red ;
2107draw q withpen pencircle scaled 10pt withcolor .625yellow ;
2108draw r withpen pencircle scaled 20pt withcolor .625white ;
2109\stopbuffer
2110
2111\startbuffer[dd]
2112draw r withpen pencircle scaled 20pt withcolor .625white ;
2113draw p withpen pencircle scaled 10pt withcolor .625red ;
2114draw q withpen pencircle scaled 10pt withcolor .625yellow ;
2115\stopbuffer
2116
2117Another case when \type {top} and friends cannot be applied in a general way is
2118the following. Consider the three paths:
2119
2120\typebuffer[a]
2121
2122We draw these paths with:
2123
2124\typebuffer[d]
2125
2126The line is drawn from center to center and since the line has a non zero width
2127and a round line cap, it extends beyond this point.
2128
2129\startlinecorrection[blank]
2130\processMPbuffer[a,d]
2131\stoplinecorrection
2132
2133If we want the line to stop at the circular paths, we can cut off the pieces that
2134extend beyond those paths.
2135
2136\typebuffer[b]
2137
2138This time we get:
2139
2140\startlinecorrection[blank]
2141\processMPbuffer[a,b,d]
2142\stoplinecorrection
2143
2144Due to the thicker line width used when drawing the straight line, part of that
2145line is still visible inside the circles. So, we need to clip off a bit more.
2146
2147\typebuffer[c]
2148
2149The \type {point ... on} operation is a \METAFUN\ macro that takes a dimension.
2150
2151\startlinecorrection[blank]
2152\processMPbuffer[a,b,c,d]
2153\stoplinecorrection
2154
2155In order to save you some typing, \METAFUN\ provides a macro \type {cutends} that
2156does the same job:
2157
2158\typebuffer[cc]
2159
2160This time we draw the path in a different order:
2161
2162\typebuffer[dd]
2163
2164That way we hide the still remaining overlapping part of the line.
2165
2166\startlinecorrection[blank]
2167\processMPbuffer[a,b,cc,dd]
2168\stoplinecorrection
2169
2170\stopsection
2171
2172\startsection[title={Directions}]
2173
2174\index{directions}
2175
2176Quite often you have to tell \METAPOST\ in what direction a line should be drawn.
2177A direction is specified as a vector. There are four predefined vectors: \type
2178{up}, \type {down}, \type {left}, \type {right}. These are defined as follows:
2179
2180\starttyping
2181pair up, down, left, right ;
2182up = down = (0,1) ; right = left = (1,0) ;
2183\stoptyping
2184
2185We can use these predefined pairs as specifications and in calculations.
2186
2187\startbuffer
2188dotlabel.top("up" , up * 1cm) ;
2189dotlabel.bot("down" , down * 1cm) ;
2190dotlabel.lft("left" , left * 1cm) ;
2191dotlabel.rt ("right", right * 1cm) ;
2192
2193drawoptions (withpen pencircle scaled .25mm withcolor .625 red) ;
2194
2195drawarrow origin up * 1cm ;
2196drawarrow origin down * 1cm ;
2197drawarrow origin left * 1cm ;
2198drawarrow origin right * 1cm ;
2199\stopbuffer
2200
2201\typebuffer
2202
2203\startlinecorrection[blank]
2204\processMPbuffer
2205\stoplinecorrection
2206
2207This graphic can also be defined in a more efficient (but probably more cryptic)
2208way. The next definition demonstrates a few nice tricks. Instead of looping over
2209the four directions, we loop over their names. Inside the loop we convert these
2210names, or strings, into a pair by scanning the string using \type {scantokens}.
2211The \type {freedotlabel} macro is part of \METAFUN\ and takes three arguments: a
2212label string (or alternatively a picture), a point (location), and the \quote
2213{center of gravity}. The label is positioned in the direction opposite to this
2214center of gravity.
2215
2216\startbuffer
2217pair destination ;
2218for whereto = "up", "down", "left", "right" :
2219 destination := scantokens(whereto) * 1cm ;
2220 freedotlabel(whereto, destination, origin) ;
2221 drawarrow origin destination
2222 withpen pencircle scaled .25mm withcolor .625 red ;
2223endfor ;
2224\stopbuffer
2225
2226\typebuffer
2227
2228So, in this code fragment, we use the string as string and (by means of \type
2229{scantokens}) as a point or vector.
2230
2231\startlinecorrection[blank]
2232\processMPbuffer
2233\stoplinecorrection
2234
2235The previous definition is a stepping stone to the next one. This time we dont
2236use points, but the \type {dir} command. This command converts an angle into an
2237unitvector.
2238
2239\startbuffer
2240pair destination ;
2241for whereto = 0 step 30 until 330 :
2242 destination := dir(whereto) * 1.5cm ;
2243 freedotlabel(decimal whereto, destination, origin) ;
2244 drawarrow origin destination
2245 withpen pencircle scaled .25mm withcolor .625 red ;
2246endfor ;
2247\stopbuffer
2248
2249\typebuffer
2250
2251In \METAPOST\ the angles go counter clockwise, which is not that illogical if you
2252look at it from the point of view of vector algebra.
2253
2254\startlinecorrection[blank]
2255\processMPbuffer
2256\stoplinecorrection
2257
2258\stopsection
2259
2260\startsection[title={Analyzing pictures}]
2261
2262\index{picturesanalyzing}
2263
2264{\em Unless you really want to know all details, you can safely skip this
2265section. The \METAPOST\ features discussed here are mainly of importance when you
2266write (advanced) macros.}
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382We can decompose \METAPOST\ pictures using a \type {within} loop. You may wonder
2383if such a \type {within} loop construct has any real application, and as you can
2384expect, it has. In \in {section} [sec:color circles] a macro is defined that
2385draws a colored circle. If you want the inverted alternative, you can pass the
2386inverted color specification, but wouldnt it be more convenient if there was an
2387operator that did this for you automatically? Unfortunately there isnt one so we
2388have to define one ourselves in a macro.
2389
2390\startbuffer
2391colorcircle(4cm,(.4,.6,.8),(.4,.8,.6),(.6,.4,.8)) ;
2392addto currentpicture also inverted currentpicture shifted (5cm,0) ;
2393\stopbuffer
2394
2395\startlinecorrection[blank]
2396\processMPbuffer
2397\stoplinecorrection
2398
2399These circles were drawn using:
2400
2401\typebuffer
2402
2403When we \type {draw} a path, or stroke a path, as it is called officially, we
2404actually perform an addition:
2405
2406\starttyping
2407addto currentpicture doublepath somepath
2408\stoptyping
2409
2410The \type {fill} command is actually:
2411
2412\starttyping
2413addto currentpicture contour somepath
2414\stoptyping
2415
2416We will need both \type {doublepath} and \type {contour} operations in the
2417definition of \type {inverted}.
2418
2419When \METAPOST\ has digested a path into a picture, it keeps track of some
2420characteristics. We can ask for them using \type {part...} operators. The
2421following operators can be applied to a transform vector (one of \METAPOSTs data
2422types), but also to a picture. Say that we have drawn a circle:
2423
2424\startbuffer[a]
2425draw fullcircle
2426 xscaled 3cm yscaled 2cm
2427 dashed dashpattern(on 3mm off 3mm)
2428 withpen pencircle scaled 1mm
2429 withcolor .625red ;
2430picture p ; p := currentpicture ;
2431\stopbuffer
2432
2433\typebuffer[a]
2434
2435This circle looks like:
2436
2437\startlinecorrection[blank]
2438\processMPbuffer[a]
2439\stoplinecorrection
2440
2441We can now ask for some of the characteristics of \type {currentpicture}, like
2442its color. We could write the values to the log file, but it is more convenient
2443to put them on paper.
2444
2445\startbuffer[b]
2446label.rt("redpart: " decimal redpart p, (4cm,.5cm)) ;
2447label.rt("greenpart: " decimal greenpart p, (4cm, 0cm)) ;
2448label.rt("bluepart: " decimal bluepart p, (4cm,.5cm)) ;
2449\stopbuffer
2450
2451\typebuffer[b]
2452
2453Here the \type {} glues strings together, while the decimal operator converts a
2454number into a string.
2455
2456The result has no typographic beauty <keep in mind that here we use \METAPOST\
2457to typeset the text>but the result serves its purpose.
2458
2459\startlinecorrection[blank]
2460\processMPbuffer[a,b]
2461\stoplinecorrection
2462
2463We can also ask for the path itself (\type {pathpart}), the pen (\type {penpart})
2464and the dashpattern (\type {dashpart}), but these can only be assigned to
2465variables of the corresponding type.
2466
2467A path can be stroked or filled, in which case it is a cyclic path. It can have a
2468non natural bounding box, be a clip path, consist of line segments or contain
2469text. All these characteristics can be tested.
2470
2471\startbuffer[b]
2472label.rt("filled: " condition filled p, (4cm,1.25cm)) ;
2473label.rt("stroked: " condition stroked p, (4cm,0.75cm)) ;
2474label.rt("textual: " condition textual p, (4cm,0.25cm)) ;
2475label.rt("clipped: " condition clipped p, (4cm,0.25cm)) ;
2476label.rt("bounded: " condition bounded p, (4cm,0.75cm)) ;
2477label.rt("cycle: " condition cycle pathpart p, (4cm,1.25cm)) ;
2478\stopbuffer
2479
2480\typebuffer[b]
2481
2482\startlinecorrection[blank]
2483\processMPbuffer[a,b]
2484\stoplinecorrection
2485
2486In this code snippet, \type {condition} is a macro that takes care of translating
2487a boolean value into a string (like \type {decimal} does with a numeric value).
2488
2489\starttyping
2490def condition primary b =
2491 if b : "true" else : "false" fi
2492enddef ;
2493\stoptyping
2494
2495Clip paths and bounding boxes are kind of special in the sense that they can
2496obscure components. The following examples demonstrate this. In case of a clip
2497path or bounding box, the \type {pathpart} operator returns this path. In any
2498case that asking for a value does not make sense <a clipping path for instance
2499has no color> a zero (null) value is returned.
2500
2501\startbuffer[b]
2502n := 1 ;
2503for i within currentpicture : n := n 1 ;
2504 label("n: " decimal n " "
2505 "length: " decimal length i " "
2506 "stroked: " condition stroked i " "
2507 "clipped: " condition clipped i " "
2508 "bounded: " condition bounded i , (0,n*.5cm)) ;
2509endfor ;
2510\stopbuffer
2511
2512\startbuffer[c]
2513\startlinecorrection[blank]
2514\framed[offset=overlay,frame=off,background=color,backgroundcolor=gray]{\processMPbuffer[a,b]}
2515\stoplinecorrection
2516\stopbuffer
2517
2518\startbuffer[a]
2519draw fullcircle withpen pencircle scaled 6mm ;
2520clip currentpicture to fullcircle ;
2521setbounds currentpicture to fullcircle ;
2522\stopbuffer
2523
2524\typebuffer[a] \getbuffer[c]
2525
2526\startbuffer[a]
2527draw fullcircle withpen pencircle scaled 6mm ;
2528setbounds currentpicture to fullcircle ;
2529clip currentpicture to fullcircle ;
2530\stopbuffer
2531
2532\typebuffer[a] \getbuffer[c]
2533
2534\startbuffer[a]
2535clip currentpicture to fullcircle ;
2536draw fullcircle withpen pencircle scaled 6mm ;
2537setbounds currentpicture to fullcircle ;
2538\stopbuffer
2539
2540\typebuffer[a] \getbuffer[c]
2541
2542\startbuffer[a]
2543clip currentpicture to fullcircle ;
2544setbounds currentpicture to fullcircle ;
2545draw fullcircle withpen pencircle scaled 6mm ;
2546\stopbuffer
2547
2548\typebuffer[a] \getbuffer[c]
2549
2550\startbuffer[a]
2551setbounds currentpicture to fullcircle ;
2552clip currentpicture to fullcircle ;
2553draw fullcircle withpen pencircle scaled 6mm ;
2554\stopbuffer
2555
2556\typebuffer[a] \getbuffer[c]
2557
2558\startbuffer[a]
2559setbounds currentpicture to fullcircle ;
2560draw fullcircle withpen pencircle scaled 6mm ;
2561clip currentpicture to fullcircle ;
2562\stopbuffer
2563
2564\typebuffer[a] \getbuffer[c]
2565
2566The description lines were generated by the following loop:
2567
2568\typebuffer[b]
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646The textual capabilities built in \METAPOST\ are rather limited but in \CONTEXT\
2647we have overloaded the relevant operators. There we hook into the normal font
2648handler. The native text related operators are:
2649
2650\starttyping
2651draw "MetaFun" infont "somefont" scaled 2 rotated 30 slanted .5 ;
2652draw btex MetaFun etex scaled 2 rotated 30 slanted .5 ;
2653\stoptyping
2654
2655The \type {infont} operator directly calls for a font and in stock \METAPOST\ is
2656limited to (eight bit) \TYPEONE\ fonts. In \CONTEXT\ you can do this:
2657
2658\startbuffer[a]
2659draw "MetaFun" infont "SerifBold*default" xscaled 5 rotated 5 slanted .5 ;
2660\stopbuffer
2661
2662\typebuffer[a]
2663
2664The specification is a regular \CONTEXT\ font specification.
2665
2666\startlinecorrection[blank]
2667\processMPbuffer[a]
2668\stoplinecorrection
2669
2670The \type {btex ... etex} variant in normal \METAPOST\ delegates to \TEX\ and in \MKII\
2671indeed we filter them and process them between runs (or at runtime). In \MKIV\ they are
2672also handled by \TEX\ but in an even more integrated and immediate way.
2673
2674The two primitives \type {textpart} and \type {fontpart} that can be used to disassemble
2675a picture dont apply to \METAFUN\ as contrary to \METAPOST\ we dont convert the result
2676to a picture. In later chapters we will discuss text in more detail.
2677
2678From the previous examples it may be clear that each picture has some associated
2679data stored with it. From the \type {bounded} boolean test we can conclude that
2680the bounding box is part of this data. Internally \METAPOST\ keeps track of two
2681bounding boxes: the natural one, and the forced one. The forced one is actually a
2682component of the picture which applies to all previously added graphics. You can
2683calculate the bounding box from the \type {llcorner} and \type {urcorner} or if
2684you like \type {ulcorner} and \type {lrcorner} and the \METAFUN\ command \type
2685{boundingbox} does so.
2686
2687The four corners that make up the bounding box are either the natural ones, or
2688the ones forced by \type {setbounds}. You can force \METAPOST\ to report the
2689natural ones by setting \type {truecorners} to1. The next example demonstrates
2690this feature.
2691
2692\startbuffer
2693pickup pencircle scaled 2mm ; path p, q ;
2694draw fullcircle
2695 scaled 4cm slanted .5 withcolor .625white ;
2696setbounds currentpicture to
2697 boundingbox currentpicture enlarged 5mm ;
2698interim truecorners := 0 ; p := boundingbox currentpicture ;
2699interim truecorners := 1 ; q := boundingbox currentpicture ;
2700pickup pencircle scaled 1mm ;
2701draw p withcolor .625red ;
2702draw q withcolor .625yellow ;
2703\stopbuffer
2704
2705\typebuffer
2706
2707We use \type {interim} because \type {truecorners} is an internal \METAPOST\
2708variable.
2709
2710\startlinecorrection[blank]
2711\processMPbuffer
2712\stoplinecorrection
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795\stopsection
2796
2797\startsection[title={Filling}]
2798
2799\index{filling}
2800\index{reversing}
2801
2802In most cases a path ends up being drawn or filled. When filling a path, it
2803doesnt matter in what direction the path runs, as long as its closed youre
2804fine. You can however change the direction any time along the path. Here is an
2805example of what happens when you fill a path that is partially reversed.
2806
2807\startbuffer
2808fill fullsquare rotated 45 scaled 2cm
2809 withcolor .625 red ;
2810fill fullcircle scaled 2cm reverse fullcircle scaled 1cm cycle
2811 withcolor .625 yellow ;
2812\stopbuffer
2813
2814\typebuffer
2815
2816Youll notice that the inner circle is not filled:
2817
2818\startlinecorrection[blank]
2819\processMPbuffer
2820\stoplinecorrection
2821
2822Now watch the following:
2823
2824\startbuffer
2825fill
2826 fullsquare rotated 45 scaled 2cm
2827 fullcircle scaled 2cm
2828 cycle
2829 withcolor .625 red ;
2830\stopbuffer
2831
2832\typebuffer
2833
2834This results in:
2835
2836\startlinecorrection[blank]
2837\processMPbuffer
2838\stoplinecorrection
2839
2840Compare this with:
2841
2842\startbuffer
2843fill
2844 fullsquare rotated 45 scaled 2cm
2845 reverse fullcircle scaled 2cm cycle
2846 cycle
2847 withcolor .625 red ;
2848\stopbuffer
2849
2850\typebuffer
2851
2852giving:
2853
2854\startlinecorrection[blank]
2855\processMPbuffer
2856\stoplinecorrection
2857
2858The normal filling happens according to the nonzero winding rule. An alternative is the
2859oddeven rule. There we dont need the reverse trick:
2860
2861\startbuffer
2862eofill fullsquare rotated 45 scaled 2cm
2863 fullcircle scaled 2cm cycle
2864 withcolor .625 red ;
2865\stopbuffer
2866
2867\typebuffer
2868
2869The \type {eofill} is a \METAFUN\ extension. Hopefully the next explains a bit
2870how this works (you can find explanations on the Internet).
2871
2872\startlinecorrection[blank]
2873\processMPbuffer
2874\stoplinecorrection
2875
2876\startuseMPgraphic{demo}
2877 def DrawIt(text how) =
2878 path p ; p := ((0,0) .. (1,0) .. (1,1) .. (0,1) .. (1,0) .. (2,1) .. cycle) scaled 2cm ;
2879 how p withcolor .625 yellow ;
2880 draw p withcolor .625 red ;
2881 for i=0 step 0.05 until 1 :
2882 fill arrowheadonpath (p,i)
2883 withcolor .625 red ;
2884 endfor ;
2885 draw (0.5,0.5) scaled 2cm withpen pencircle scaled .5mm withcolor .375 white ;
2886 draw ((0.5,0.5) scaled 2cm -- llcorner p) withpen pencircle scaled .5mm withcolor .375 white ;
2887 draw (1.5,1.5) scaled 2cm withpen pencircle scaled .5mm withcolor .375 white ;
2888 draw ((1.5,1.5) scaled 2cm -- urcorner p) withpen pencircle scaled .5mm withcolor .375 white ;
2889 enddef ;
2890\stopuseMPgraphic
2891
2892\startlinecorrection[blank]
2893 \startcombination[distance=4em]
2894 {\startMPcode \includeMPgraphic{demo} DrawIt(eofill) \stopMPcode} {\type{eofill}}
2895 {\startMPcode \includeMPgraphic{demo} DrawIt(fill) \stopMPcode} {\type{fill}}
2896 \stopcombination
2897\stoplinecorrection
2898
2899In the case of a normal fill, the nonzero winding rule is applied: a winding
2900number is calculated by subtracting 1 each time the line (from inside an area to
2901someplace outside) is crossed clockwise while 1 is added each time we cross
2902anticlockwise. When the total is non zero the area is filled. Here we run in one
2903direction and therefore we always get a fill. In the previous example where we
2904used a reverse, an anticlockwise crossing was nilled by a clockwise one.
2905
2906The leftmost shape uses \type {eofill} and therefore the oddeven rule gets
2907applied. This time we follow the line and when it gets crossed en even number of
2908times the area will not be filled.
2909
2910Here is another example:
2911
2912\startbuffer
2913eofill for i=1 upto 12: fullcircle scaled ((i12)*cm) endfor cycle ;
2914\stopbuffer
2915
2916\typebuffer
2917
2918The successive larger circle are unfilled and basically form one path:
2919
2920\startlinecorrection[blank]
2921\processMPbuffer
2922\stoplinecorrection
2923
2924A glyph is often constructed from more than one path and eventually the shape is
2925filled with an oddeven fill (\type {eofill}) operation. Take the following
2926sequence:
2927
2928\startbuffer
2929pickup pencircle scaled 1mm ;
2930draw fullsquare scaled 2cm ;
2931draw fullsquare scaled 2cm shifted (1cm,0) ;
2932draw fullsquare scaled 2cm shifted (0,1cm) ;
2933\stopbuffer
2934
2935\typebuffer
2936
2937\startlinecorrection[blank]
2938\processMPbuffer
2939\stoplinecorrection
2940
2941We can use a sequence of \type {nofill} ending with a \type {eofill} to create
2942a combined shape. This is not done in \METAPOST\ but in the backend.
2943
2944\startbuffer
2945nofill fullsquare scaled 2cm ;
2946nofill fullsquare scaled 2cm shifted (1cm,0) ;
2947eofill fullsquare scaled 2cm shifted (0,1cm) ;
2948\stopbuffer
2949
2950\typebuffer
2951
2952\startlinecorrection[blank]
2953\processMPbuffer
2954\stoplinecorrection
2955
2956As this is used for glyphs, we demonstrate this mechanism with a simple \type {O}
2957shape:
2958
2959\startbuffer
2960nofill fullcircle xyscaled (2cm,3cm) ;
2961eofill fullcircle xyscaled (1cm,2cm) ;
2962\stopbuffer
2963
2964\typebuffer
2965
2966\startlinecorrection[blank]
2967\processMPbuffer
2968\stoplinecorrection
2969
2970Another backend related feature is \type {fillup}. This is just a combination
2971of a fill and a draw in one go. It can save some bytes in the output file.
2972
2973\startbuffer
2974draw image (
2975 pickup pencircle scaled 5mm ;
2976 fill fullsquare scaled 2cm ;
2977 draw fullsquare scaled 2cm ;
2978 fillup fullsquare scaled 2cm shifted (4cm,0) ;
2979) withcolor .625red ;
2980\stopbuffer
2981
2982\typebuffer
2983
2984\startlinecorrection[blank]
2985\processMPbuffer
2986\stoplinecorrection
2987
2988\stopsection
2989
2990\startsection[title={Pitfalls}]
2991
2992When writing macros, you need to be careful in what
2993operations apply to what object. There is for instance a
2994difference between the following code:
2995
2996\startbuffer
2997pickup pencircle scaled 2pt ;
2998draw (0,0)(0,1)(1,1) scaled 1cm withcolor .625 red ;
2999draw ((0,0)(0,1)(1,1)) scaled 2cm withcolor .625 yellow ;
3000\stopbuffer
3001
3002\typebuffer
3003
3004\startlinecorrection[blank]
3005\processMPbuffer
3006\stoplinecorrection
3007
3008The \type {scaled} operates on the previous expression which in the first case is
3009the point \type {(1,1)} and in the second case the whole path.
3010
3011\startbuffer
3012pickup pencircle scaled 2pt ;
3013draw (0,0)(0,1)(1,1)cycle scaled 1cm withcolor .625 red ;
3014draw ((0,0)(0,1)(1,1)cycle) scaled 2cm withcolor .625 yellow ;
3015\stopbuffer
3016
3017\typebuffer
3018
3019\startlinecorrection[blank]
3020\processMPbuffer
3021\stoplinecorrection
3022
3023Here the last element in the first case is not the cycle, and the next
3024alternative does not help us much in discovering what is going on. (Well, at
3025least something {\em is} going on, because the result seems to have some
3026dimensions.)
3027
3028\startbuffer
3029pickup pencircle scaled 2pt ;
3030draw (1,1)cycle scaled 1cm withcolor .625 red ;
3031draw ((1,1)cycle) scaled 1cm withcolor .625 yellow ;
3032\stopbuffer
3033
3034\typebuffer
3035
3036\startlinecorrection[blank]
3037\processMPbuffer
3038\stoplinecorrection
3039
3040The next lines demonstrate that were dealing with the dark sides of \METAPOST,
3041and from that we may conclude that in case of doubt its best to add parenthesis
3042when such fuzzy situations threaten to occur.
3043
3044\startbuffer
3045pickup pencircle scaled 2pt ;
3046draw (0,1)(1,1)cycle scaled 1cm withcolor .625 red ;
3047draw ((0,1)(1,1)cycle) scaled 1cm withcolor .625 yellow ;
3048\stopbuffer
3049
3050\typebuffer
3051
3052\startlinecorrection[blank]
3053\processMPbuffer
3054\stoplinecorrection
3055
3056There are more cases where the result may surprise you. Take the following code:
3057
3058\startbuffer
3059drawarrow ((0,0)(10,0))
3060 withpen pencircle scaled 2pt
3061 withcolor red randomized (.4,.9) ;
3062currentpicture := currentpicture scaled 8 ;
3063\stopbuffer
3064
3065\typebuffer
3066
3067\startlinecorrection[blank]
3068\processMPbuffer
3069\stoplinecorrection
3070
3071The arrow is made up out of two pieces and each piece gets a different shade of
3072red. This is because the attributes are collected and applied to each of the
3073components that make up the arrow. Because for each component the attribute code
3074is expanded again, we get two random colors. One way around this is to apply the
3075color afterwards.
3076
3077\startbuffer
3078draw
3079 image (drawarrow ((0,0)(10,0)) withpen pencircle scaled 2pt)
3080 scaled 8 withcolor red randomized (.4,.9) ;
3081\stopbuffer
3082
3083\typebuffer
3084
3085\startlinecorrection[blank]
3086\processMPbuffer
3087\stoplinecorrection
3088
3089Here the \type {image} macro creates a picture and as you can see, this provides
3090a way to draw within a draw operation.
3091
3092Once you see the benefits of \type {image}, you will use it frequently. Another
3093handy (at first sight strange) macro is \type {hide}. You can use this in
3094situations where you dont want code to interfere.
3095
3096\starttyping
3097def mydraw text t =
3098 boolean error ; error := false ;
3099 def withpencil expr p = hide (error := true) enddef ;
3100 draw t ;
3101 if error : message "pencils are not supported here" fi ;
3102enddef ;
3103mydraw fullcircle scaled 10cm withpencil sharp ;
3104\stoptyping
3105
3106Here, setting the boolean normally interferes with the draw operation, but by
3107hiding the assignment, this code becomes valid. This code will bring the message
3108to your terminal and log file.
3109
3110Once you start using expressions you have a good chance of encountering messages
3111with regard to redundant expressions. The following code is for instance a
3112recipe for problems:
3113
3114\starttyping
3115z1 = (1,0) ; z1 = (2,0) ;
3116\stoptyping
3117
3118Changing the \type {=} into \type {:=} helps, but this may not be what you want.
3119
3120Because the \type {z}variables are used frequently, they are reset each figure.
3121You can also reset them yourself, using the \type {clearxy} macro. The \METAFUN\
3122version clears all \type {z}variables, unless you explictly specify what
3123variables to reset. \footnote {This version resulted from a discussion on the
3124\METAFONT\ discussion list and is due to Bogus\l{}aw Jackowski.} If you want to
3125play with this macro, see what happens when you run the following code:
3126
3127\starttyping
3128show x0 ; z0 = (10,10) ;
3129show x0 ; x0 := whatever ; y0 := whatever ;
3130show x0 ; z0 = (20,20) ;
3131show x0 ; clearxy 0 ;
3132show x0 ; z0 = (30,30) ;
3133\stoptyping
3134
3135So, the following calls are all legal:
3136
3137\starttyping
3138clearxy ; clearxy 1 ; clearxy 1, 8, 10 ;
3139\stoptyping
3140
3141Keep in mind that for each figure a full clear is done anyway. You should not
3142confuse this command with \type {clearit}, which clears \type {currentpicture}.
3143
3144\stopsection
3145
3146\startsection[title={\TeX\ versus \MetaPost}]
3147
3148If you are defining your own \TEX\ and \METAPOST\ macros, you will notice that
3149there are a couple of essential differences between the two macro languages. In
3150\TEX\ the following code is invalid. \footnote {In \ETEX\ the calculation can be
3151done in less lines using a \type {\numexpr}.}
3152
3153\starttyping
3154\def\fancyplied#1
3155 {\ifnum#1=0
3156 \message{zero argument}
3157 \fi
3158 \count0=#1 \multiply \count0 by \count0
3159 \count2=#1 \multiply \count2 by 2
3160 \count4=#1 \divide \count4 by 2
3161 \advance \count0 by \count2
3162 \advance \count0 by \count4
3163 \count4 }
3164\hskip \fancyplied{3} pt
3165\stoptyping
3166
3167This is because \TEX\ is very strict in what tokens it expects next. In
3168\METAPOST\ however, you can use \type {vardef}d macros to hide nasty
3169intermediate calculations.
3170
3171\starttyping
3172vardef fancyplied expr x =
3173 if x=0 : message "x is zero" ; (x*x2xx2)
3174enddef ;
3175a := a shifted (fancyplied 3pt,0) ;
3176\stoptyping
3177
3178Hiding intermediate calculations and manipulations is a very strong point of
3179\METAPOST.
3180
3181Another important difference between both languages is the way grouping is
3182implemented. Because \TEX\ is dealing with a flow of information, strong grouping
3183is a must and therefore part of the language. Occasionally you run into
3184situations where you wished that you could reach over a group (for instance in
3185order to pass a value).
3186
3187In \METAPOST\ grouping behaves quite different. First of all, it provides the
3188mechanism that hides processing from the current flow. The previously mentioned
3189\type {vardef} is implicitly grouped. Contrary to \TEX, in \METAPOST\ all
3190assignments are global by default, even in a group. If you assign a variable
3191inside a group it is persistent unless you first save the variable (or macro)
3192using the \type {save} operator.
3193
3194So, in the next code snippet, the value of \type {\value} inside the box is {\em
3195no} but after the box is typeset, it will be {\em yes} again.
3196
3197\starttyping
3198\def\value{yes} \hbox{\def\value{no}\value} \value
3199\stoptyping
3200
3201To make a value local in \METAPOST, the following code is needed.
3202
3203\starttyping
3204string value ; value := "yes" ;
3205def intermezzo
3206 begingroup ;
3207 save value ; string value ; value := "no" ;
3208 endgroup ;
3209enddef ;
3210\stoptyping
3211
3212Once you start writing your own \METAPOST\ macros, you will appreciate this
3213\quote {always global} behaviour. As with other differences between the two
3214languages, they make sense if you look at what the programs are supposed to do.
3215
3216\stopsection
3217
3218\startsection[title={Internals and Interims}]
3219
3220\index{internals}
3221\index{interims}
3222
3223Related to grouping is the internal numeric datatype. When numeric variables are
3224defined as interim, you can quickly overload them inside a group.
3225
3226\starttyping
3227newinternal mynumber ; mynumber := 1 ;
3228
3229begingroup ; ... interim mynumber := 0 ; ... ; endgroup ;
3230\stoptyping
3231
3232You can only \type {interim} a variable if it is already defined using \type
3233{newinternal}.
3234
3235Among the \METAPOST\ macros is one called \type {drawdot}. This macro is kind of
3236redundant because, at least at first sight, you can use draw to achieve the same
3237result. There is however a very subtle difference: a dot is slightly larger than
3238a drawn point. We guess that its about the device pixel, so you may not even
3239notice it. It may even be due to differences in accuracy of the methods to render
3240them.
3241
3242\startbuffer
3243pickup pencircle scaled 50pt ;
3244drawdot origin shifted (120pt,0) ; draw origin shifted (60pt,0) ;
3245drawdot origin ; draw origin withcolor white ;
3246setbounds currentpicture to boundingbox currentpicture enlarged 1pt ;
3247\stopbuffer
3248
3249\typebuffer
3250
3251\startlinecorrection[blank]
3252\processMPbuffer
3253\stoplinecorrection
3254
3255\stopsection
3256
3257\startsection[title=Named colors]
3258
3259The \type {withcolor} operator accepts a color expression but in \METAFUN\ it
3260also accepts a string indicating a color defined at the \TEX\ end. Most helpers
3261that deal with colors are able to deal with named colors as well. Here are some
3262examples. First we define a few colors:
3263
3264\startbuffer
3265\definecolor[MyColor1][r=.5]
3266\definecolor[MyColor2][g=.5]
3267\definecolor[MyColor3][b=.5]
3268\definecolor[MyColor4][s=.8]
3269\stopbuffer
3270
3271\typebuffer \getbuffer
3272
3273Here we access them:
3274
3275\startbuffer
3276fill fullcircle scaled 12 withcolor "MyColor1" ;
3277fill fullcircle scaled 10 withcolor "MyColor2" ;
3278fill fullcircle scaled 8 withcolor complementary "MyColor3" ;
3279fill fullcircle scaled 6 withcolor complemented "MyColor3" ;
3280fill fullcircle scaled 4 withcolor "MyColor4" randomized 2 ;
3281fill fullcircle scaled 2 withcolor "MyColor4" randomized 2 ;
3282addbackground
3283 withcolor .5[resolvedcolor("MyColor4"),resolvedcolor("MyColor2")] ;
3284currentpicture := currentpicture ysized 4cm ;
3285\stopbuffer
3286
3287\typebuffer
3288
3289And get:
3290
3291\startlinecorrection[blank]
3292\processMPbuffer
3293\stoplinecorrection
3294
3295\stopsection
3296
3297\startsection[title=Formatted text]
3298
3299Text support in \METAFUN\ has evolved quite a bit over years. For compatibility
3300reasons we keep old methods around but in practice one can probably do all with
3301the following:
3302
3303\starttabulate[Tp]
3304\NC textext[.anchor](str) \NC position a text relative to the origin \NC \NR
3305\NC thetextext[.anchor](str,pos) \NC position a text relative to the given position \NC \NR
3306\NC rawtextext[.anchor](str,pos) \NC idem but with less checking \NC \NR
3307\stoptabulate
3308
3309If needed all functionality could be combined in one call (textext) but we keep
3310it this way.
3311
3312You need to keep in mind that text in \METAPOST\ is not a first class object but
3313something virtual that is known to \METAFUN\ as something with path like properties
3314but is actually dealt with in the backend. This means that timing is important.
3315
3316\starttyping
3317\startMPinitializations
3318picture p ; p := image(draw textext("Foo"););
3319\stopMPinitializations
3320
3321\startMPcode
3322 picture q ; q := image(draw textext("Bar"););
3323 picture r ; r := image(draw textext("Gnu"););
3324 draw p ;
3325 draw q shifted (2cm,0) ;
3326 draw r shifted (4cm,0) ;
3327\stopMPcode
3328\stoptyping
3329
3330This will work out well because an initialization is part of a figure, but
3331this will fail:
3332
3333\starttyping
3334\startMPinclusions
3335picture p ; p := image(draw textext("Foo"););
3336\stopMPinclusions
3337\stoptyping
3338
3339because inclusions happen before the local textexts get initialized and
3340due to the multipass implementation are not seeN a second time. The order of
3341processing is:
3342
3343\starttabulate[lcc]
3344\BC action \BC first pass \BC second pass \NC \NR
3345\NC definitions \NC yes \NC \NC \NR
3346\NC extensions \NC yes \NC \NC \NR
3347\NC inclusions \NC yes \NC \NC \NR
3348\NC begin figure \NC yes \NC yes \NC \NR
3349\NC initializations \NC yes \NC yes \NC \NR
3350\NC metapost code \NC yes \NC yes \NC \NR
3351\NC end figure \NC yes \NC yes \NC \NR
3352\stoptabulate
3353
3354The graph package (that comes with \METAPOST) has some pseudo typesetting on
3355board needed to format numbers. Because we dont want to interfere with the
3356definitions of macros used in that package we provide another set of macros for
3357formatting: \type {fmttext}, \type {thefmttext} and \type {rawfmttext}.
3358
3359\startbuffer
3360\startMPcode
3361draw thefmttext("\bf@3.2f done",123.45678) withcolor darkred ;
3362\stopMPcode
3363\stopbuffer
3364
3365\typebuffer
3366
3367Here we pass one variable to the format but there can be more: \inlinebuffer. In
3368\LUA\ the \type {
3369\TEX\ and \LUA\ which is why we use \type {@} instead. The formatting is done
3370with the formatters subsystem which is an extension to the regular \LUA\ \type
3371{format} function. More information can be found in \type {clfmkiv.pdf} but one
3372extension is not mentioned there: \type {
3373argument by default but optionally can take one or two extra arguments: the
3374format of the base number and one for the exponent. The following code
3375demonstrates this:
3376
3377\startbuffer
3378\startMPcode{doublefun}
3379draw image (
3380 draw thefmttext.rt("@!texexp!", 10.4698E30, (0,-1LineHeight)) ;
3381 draw thefmttext.rt("@1!texexp!",10.4698E30, (0,-2LineHeight)) ;
3382 draw thefmttext.rt("@2!texexp!",10.4698E30,"@2.3f", (0,-3LineHeight)) ;
3383 draw thefmttext.rt("@3!texexp!",10.4698E30,false,"@2i", (0,-4LineHeight)) ;
3384 draw thefmttext.rt("@3!texexp!",10.4698E30,"@2.3f","@2i",(0,-5LineHeight)) ;
3385) withcolor darkblue ;
3386\stopMPcode
3387\stopbuffer
3388
3389\typebuffer
3390
3391We switch to double mode because we use large numbers.
3392
3393\startlinecorrection[blank]
3394 \getbuffer
3395\stoplinecorrection
3396
3397Of course this extra formatter is also supported in the \type {context}
3398command:
3399
3400\startbuffer
3401\startluacode
3402context("%!texexp!, ", 10.4698E30)
3403context("%1!texexp!, ", 10.4698E30)
3404context("%2!texexp!, ", 10.4698E30,"@2.3f")
3405context("%3!texexp! and ",10.4698E30,false,"@2i")
3406context("%3!texexp!", 10.4698E30,"@2.3f","@2i")
3407\stopluacode
3408\stopbuffer
3409
3410\typebuffer
3411
3412This gives: \inlinebuffer . In \in {figure} [fig:formatters] we see some more
3413formatters.
3414
3415\startbuffer
3416for i=1 upto 12 :
3417 draw
3418 thefmttext("\letterpercent 3!date!","month,space,year",2019,i)
3419 shifted (0,i *cm 2);
3420 draw
3421 thefmttext("@3!date!","month,space,year",2019,i)
3422 shifted (4cm,i *cm 2);
3423endfor ;
3424
3425for i=1 upto 20 :
3426 draw
3427 thefmttext(decimal i)
3428 shifted (1cm,i2*cm);
3429 draw
3430 thefmttext("@!month!",i)
3431 shifted (4cm,i2*cm);
3432 draw
3433 thefmttext("@!weekday!",i)
3434 shifted (7cm,i2*cm);
3435 draw
3436 thefmttext("@!monthshort!",i)
3437 shifted (10cm,i2*cm);
3438 draw
3439 thefmttext("@3!dayoftheweek!",i,1,2018)
3440 shifted (13cm,i2*cm);
3441endfor ;
3442\stopbuffer
3443
3444\typebuffer
3445
3446\startplacefigure[title=formatters,reference=fig:formatters]
3447 \framed{\scale[width=.8\textwidth]{\processMPbuffer}}
3448\stopplacefigure
3449
3450\stopsection
3451
3452\startsection[title=Lists (aka suffixed variables)]
3453
3454Sometimes graphics are constructed using lists. There are a few helpers (and
3455maybe there will be some more) that can make things a bit easier. Say that we
3456do this:
3457
3458\startbuffer
3459pair a[] ;
3460a[1] := (0,0) ; a[2] := (1,0) ;
3461a[3] := (1,1) ; a[4] := (0,1) ;
3462a[5] := (1,1) ; a[6] := (2,0) ;
3463
3464draw topath(a,) ysized 2cm
3465 withpen pencircle scaled 1mm
3466 withcolor .625red ;
3467\stopbuffer
3468
3469\typebuffer
3470
3471\startlinecorrection[blank]
3472\processMPbuffer
3473\stoplinecorrection
3474
3475The \type {topath} macro converts the list into a path, in this case an ugly one.
3476
3477Say that we want to get rid of the sixth entry. For that we can use the \type
3478{dispose} macro. You can use the dispose for any type (except a macro).
3479
3480\startbuffer
3481dispose(a[6]) ;
3482draw topath(a,) ysized 2cm
3483 withpen pencircle scaled 1mm
3484 withcolor .625yellow ;
3485\stopbuffer
3486
3487\typebuffer
3488
3489\startlinecorrection[blank]
3490\processMPbuffer
3491\stoplinecorrection
3492
3493We still have some duplicate entries here:
3494
3495\startbuffer
3496dispose(a[6]) ;
3497drawpoints topath(a,) ysized 2cm
3498 withpen pencircle scaled 1mm
3499 withcolor .625red ;
3500drawpointlabels topath(a,) ysized 2cm ;
3501\stopbuffer
3502
3503\typebuffer
3504
3505\startlinecorrection[blank]
3506\processMPbuffer
3507\stoplinecorrection
3508
3509These can be removed with:
3510
3511\startbuffer
3512uniquelist(a) ;
3513draw topath(a,) ysized 2cm
3514 withpen pencircle scaled 1mm
3515 withcolor .625yellow ;
3516drawpoints topath(a,) ysized 2cm
3517 withpen pencircle scaled 1mm
3518 withcolor .625red ;
3519drawpointlabels topath(a,) ysized 2cm ;
3520\stopbuffer
3521
3522\typebuffer
3523
3524\startlinecorrection[blank]
3525\processMPbuffer
3526\stoplinecorrection
3527
3528Sometimes a list needs to be sorted and here is the solution:
3529
3530\startbuffer
3531sortlist(a,nothing) ;
3532draw topath(a,) ysized 2cm
3533 withpen pencircle scaled 1mm
3534 withcolor .625red ;
3535\stopbuffer
3536
3537\typebuffer
3538
3539\startlinecorrection[blank]
3540\processMPbuffer
3541\stoplinecorrection
3542
3543The second argument can be an operator that takes a pair variable:
3544
3545\startbuffer
3546sortlist(a,xpart) ;
3547draw topath(a,) ysized 2cm
3548 withpen pencircle scaled 3mm
3549 withcolor .625red ;
3550sortlist(a,ypart) ;
3551draw topath(a,) ysized 2cm
3552 withpen pencircle scaled 2mm
3553 withcolor .625yellow ;
3554\stopbuffer
3555
3556\typebuffer
3557
3558\startlinecorrection[blank]
3559\processMPbuffer
3560\stoplinecorrection
3561
3562Constructing a list can be sped up with the \type {tolist} macro.
3563
3564\startbuffer
3565pair a[], b[], c[], d[] ;
3566tolist(a,1,(0,0),(1,0),(1,1),(0,1)(1,1)(2,2)) ;
3567tolist(b,0,(0,0),(1,0),(1,1),(0,1)(1,1)(2,2)) ;
3568tolist(c,(0,0),(1,0),(1,1),(0,1)(1,1)(2,2)) ;
3569tolist(d,(0,0),(1,0),(1,1)) ;
3570
3571draw image (
3572 draw topath(a,) shifted (0,0) ;
3573 draw topath(b,) shifted (3,0) ;
3574 draw topath(c,) shifted (6,0) ;
3575 draw topath(d,) shifted (9,0) ;
3576) ysized 2cm withpen pencircle scaled 1mm withcolor .625red ;
3577\stopbuffer
3578
3579\typebuffer
3580
3581\startlinecorrection[blank]
3582\processMPbuffer
3583\stoplinecorrection
3584
3585\stopsection
3586
3587\startsection[title=Segmented paths]
3588
3589\index {segmented paths}There are all kind of helpers in \METAFUN\ and some are
3590discussed here. In \in {figure} [fig:segmentedpaths] we see a few macros that
3591return a (smooth) path made from segments. You can for instance use these to do
3592things that use the points on a path, like anchoring text.
3593
3594\startbuffer
3595def DrawSomePath(text t) =
3596 drawpath t withcolor .625red ;
3597 drawpoints t withcolor white ;
3598 drawpointlabels t ;
3599enddef ;
3600
3601DrawSomePath(circularpath(5) scaled 12cm) ;
3602DrawSomePath(squarepath (5) scaled 8cm) ;
3603DrawSomePath(linearpath (5) scaled 4cm) ;
3604\stopbuffer
3605
3606\typebuffer
3607
3608\startplacefigure[title={A few segmented paths.},reference=fig:segmentedpaths]
3609 \processMPbuffer
3610\stopplacefigure
3611
3612\index {crossing paths}The following examples demonstrates two mechanisms. In the
3613image two paths are drawn on top of each other but one of them has holes where
3614the other one crosses. The \type {crossingunder} macro was written by Alan
3615Braslau as part of the node based diagram builder. In the process the arrow
3616drawing code was adapted to accept a picture.
3617
3618\startbuffer[a]
3619drawarrow image (
3620 draw ((fullcircle scaled 2.25cm) crossingunder (fullsquare scaled 2cm))
3621 withpen pencircle scaled 1mm withcolor .625green ;
3622 draw (fullsquare scaled 2cm)
3623 withpen pencircle scaled 1mm withcolor .625blue ;
3624) ;
3625drawarrow image (
3626 draw (fullsquare scaled 4cm)
3627 withpen pencircle scaled 1mm withcolor .625red ;
3628 draw ((fullcircle scaled 5cm) crossingunder (fullsquare scaled 4cm))
3629 withpen pencircle scaled 1mm withcolor .625yellow ;
3630) ;
3631\stopbuffer
3632
3633\startbuffer[b]
3634drawarrow image (
3635 draw ((fullsquare scaled 2cm) crossingunder (fullcircle scaled 2.25cm))
3636 withpen pencircle scaled 1mm withcolor .625blue ;
3637 draw (fullcircle scaled 2.25cm)
3638 withpen pencircle scaled 1mm withcolor .625green ;
3639) ;
3640drawarrow image (
3641 draw (fullcircle scaled 5cm)
3642 withpen pencircle scaled 1mm withcolor .625yellow ;
3643 draw ((fullsquare scaled 4cm) crossingunder (fullcircle scaled 5cm))
3644 withpen pencircle scaled 1mm withcolor .625red ;
3645) ;
3646\stopbuffer
3647
3648\typebuffer[a]
3649
3650The next variant uses a different order:
3651
3652\typebuffer[b]
3653
3654The results are shown in \in {figure} [fig:crossingunder]. The internal variable
3655\type {crossingscale} can be used to make the gap wider or narrower. The gap has
3656a default value of 20.
3657
3658\startplacefigure[title=Crossing paths without touching,reference=fig:crossingunder]
3659 \startcombination
3660 {\processMPbuffer[a]} {}
3661 {\processMPbuffer[b]} {}
3662 \stopcombination
3663\stopplacefigure
3664
3665\stopsection
3666
3667\startsection[title=Grouping]
3668
3669The grouping model in \METAPOST\ is kind of special. Basically anything that
3670happens in a group is processed in some nested action and doesnt interfere with
3671the outside. However, the last value put (back) into the input is picked up after
3672the group. A \type {vardef} acts that way:
3673
3674\startbuffer
3675vardef foo (expr i, j) =
3676 save ii, jj ; ii := 2*i ; jj :=j2 ;
3677 (i, j) (ii,jj)
3678enddef ;
3679
3680draw (foo(1,2) .. foo(5,1) .. foo(12,3))
3681 ysized 1cm
3682 withpen pencircle scaled 2mm
3683 withcolor darkred ;
3684
3685draw boundingbox currentpicture withcolor darkyellow ;
3686\stopbuffer
3687
3688\typebuffer
3689
3690This weird shape comes out:
3691
3692\startlinecorrection[blank]
3693 \processMPbuffer
3694\stoplinecorrection
3695We save two variables, and then give new local numerics with their names some
3696values. Then we \quote {return} a path. A \type {vardef} automatically starts
3697with a \type {begingroup} and ends with an \type {endgroup}. The next example
3698shows how we can use that grouping trick directly. The \type {} has to come
3699before the \type {begingroup}.
3700
3701\startbuffer
3702vardef turtle expr p =
3703 save a ; pair a ; a := point 0 of p ; a
3704 for i = 1 upto length(p) if cycle p : 1 fi :
3705 begingroup a := a shifted point i of p ; a endgroup
3706 endfor
3707 if cycle p : cycle fi
3708enddef ;
3709
3710draw ((0, 0) (10, 0) (100, 10) (5,20) cycle)
3711 withpen pencircle scaled 2 withcolor darkred ;
3712draw turtle ((0, 0) (10, 0) (100, 10) (5,20) cycle)
3713 withpen pencircle scaled 2 withcolor darkyellow ;
3714\stopbuffer
3715
3716\typebuffer
3717
3718Turtle graphics use relative positions. Actually they use one number and switch
3719direction but the above is okay too. Effectively we loop over the path and use
3720each point as a relative move, so we recalculate it.
3721
3722\startlinecorrection[blank]
3723 \processMPbuffer
3724\stoplinecorrection
3725
3726We could have said \type { hide(a := a shifted point i of p) a} because the
3727\type {hide} macro does that the grouping trick.
3728
3729\stopsection
3730
3731\startsection[title=External files]
3732
3733You can put code in an external file and load that one when needed. The low level
3734command is \type {input}:
3735
3736\starttyping
3737input myfile ;
3738input myfile.mp ;
3739input myfile.mpiv ;
3740input myfile.mpxl ;
3741input "myfile.mpxl" ;
3742\stoptyping
3743
3744In \CONTEXT\ we have modules and their name starts with \type {mp} and the
3745suffix can depend on what version you use (\type {mpii}, \type {mpiv}, \type
3746{mpxl}) but that will be dealt with automatically.
3747
3748\starttyping
3749loadmodule("mine") ;
3750\stoptyping
3751
3752This will locate \type {mpmine} with the proper suffix and often a module will
3753be set up to be loaded only once. For loading files \LUAMETAFUN\ provides:
3754
3755\starttyping
3756loadfile("somefile.mp") ;
3757\stoptyping
3758
3759Which is a bit more robust than the \type {input} commands that is kind of fuzzy
3760because it takes a sequence of tokens or a string. When you embed code in a
3761document source there are some environments that permit loading of definitions
3762and extensions.
3763
3764\starttyping
3765\startMPdefinitions
3766
3767\stopMPdefinitions
3768
3769\startMPextensions
3770
3771\stopMPextensions
3772\stoptyping
3773
3774\stopsection
3775
3776\startsection[title=Instances]
3777
3778The library supports several numbering models. The default is \type {scaled} that
3779uses integers that represent a (relatively small) float. Although you can go up
3780to 32K its wise to stay below 4096. The \type {double} number model supports 64
3781bit floating point and the \type {decimal} model arbitrary precision. In \LUATEX\
3782there is also \type {binary} for arbitrary precision but in \LUAMETATEX\ that
3783model is not provided.
3784
3785You can use different models and instances alongside. In \MKIV\ and \LMTX\ we have
3786a few predefined. The \type {metafun} instance is the default. Here we show the
3787ones that use \METAFUN:
3788
3789\starttyping[style=\ttx]
3790\defineMPinstance[metafun] [format=metafun,extensions=yes,initializations=yes]
3791\defineMPinstance[minifun] [format=minifun,extensions=yes,initializations=yes]
3792\defineMPinstance[extrafun] [format=metafun,extensions=yes,initializations=yes]
3793\defineMPinstance[lessfun] [format=metafun]
3794\defineMPinstance[doublefun] [format=metafun,extensions=yes,initializations=yes,method=double]
3795\defineMPinstance[decimalfun][format=metafun,extensions=yes,initializations=yes,method=decimal]
3796\defineMPinstance[mprun] [format=metafun,extensions=yes,initializations=yes]
3797\defineMPinstance[simplefun] [format=metafun,method=double]
3798\stoptyping
3799
3800All instances will load additional definitions btu extensions (expanded
3801definitions) and initializations (before each graphic) are optional.
3802
3803\starttyping
3804\startMPdefinitions
3805\stopMPdefinitions
3806
3807\startMPextensions
3808\stopMPextensions
3809
3810\startMPinitializations
3811\stopMPinitializations
3812\stoptyping
3813
3814You can search the sources of manuals and test suite for examples of usage, but here are
3815some:
3816
3817\startbuffer
3818\defineMPinstance[foo][definitions=yes]
3819\defineMPinstance[bar][definitions=yes]
3820
3821\startMPdefinitions{foo}
3822 vardef p = image (
3823 draw fullsquare scaled 1cm withcolor "darkgreen" ;
3824 draw textext("1") ;
3825 )
3826 enddef ;
3827\stopMPdefinitions
3828
3829\startMPdefinitions{bar}
3830 vardef p = image (
3831 draw (fullsquare rotated 45) scaled 1cm withcolor "darkyellow" ;
3832 draw textext("2") ;
3833 )
3834 enddef ;
3835\stopMPdefinitions
3836\stopbuffer
3837
3838\typebuffer \getbuffer
3839
3840We use both as:
3841
3842\startbuffer[demo1]
3843\startMPcode{foo}
3844 draw p ;
3845 draw image (
3846 draw fullcircle scaled 1cm withcolor "darkblue" ;
3847 draw textext("3") withcolor "darkred" ;
3848 ) ;
3849 draw p ;
3850\stopMPcode
3851\stopbuffer
3852
3853\startbuffer[demo2]
3854\startMPcode{bar}
3855 draw p ;
3856 draw image (
3857 draw fullcircle scaled 1cm withcolor "darkblue" ;
3858 draw textext("4") withcolor "darkred" ;
3859 ) ;
3860\stopMPcode
3861\stopbuffer
3862
3863\typebuffer[demo1,demo2]
3864
3865\startlinecorrection
3866\startcombination[nx=2,ny=1]
3867 {\getbuffer[demo1]} {foo}
3868 {\getbuffer[demo2]} {bar}
3869\stopcombination
3870\stoplinecorrection
3871
3872\stopsection
3873
3874\stopchapter
3875
3876\stopcomponent
3877 |