MetaPost
Contents
MetaPost is a graphical programming language, based on Donald Knuth's MetaFont. Normally MP graphics are converted to PostScript and used with dvips, but ConTeXt can use it directly with PDF (see the MP to PDF manual).
MetaPost is ConTeXt's native graphics language. MetaFun is a MetaPost module by Hans Hagen that adds a lot of extra features; it is enabled by default, so one could say that MetaFun is ConTeXt's default dialect of MetaPost.
Documentation & Tutorials
- A User's Manual for MetaPost
- Learning METAPOST by doing (this and this link are not working)
- A Beginner's Guide to METAPOST for Creating High-Quality Graphics by Troy Henderson
- MetaFun
- Lots of examples
- Color in MetaPost describes how to get color mixtures, TeX colors, and transparent effects in MetaPost graphics.
- MetaPost in ConTeXt
Using MetaPost in ConTeXt
With \startuseMPgraphic, you define a piece of graphics code that is processed anew every time the graphic is placed with \useMPgraphic. Further commands are described at MetaPost in ConTeXt.
\def\mycolor{.625red} \startuseMPgraphic{name} fill fullcircle scaled 20pt withcolor \mycolor; \stopuseMPgraphic red: \useMPgraphic{name} \def\mycolor{.625blue} blue: \useMPgraphic{name}
Different Packages, Extensions & Applications of Metapost
- MetaPlot - graph drawing
- MetaObj - object-oriented drawing, see also the page about MetaObj and Labels
- finomaton - drawing finite state automata
- statsmac - metapost macros for statistics graphs
- MetaUML - MetaPost library for typesetting UML diagrams
- METAGRAPH - drawing (un)directed graphs
3D support
TODO: needs major review (See: To-Do List) |
MetaPost relatives
Font Creation
3D drawing
- Asymptote - inspired by MetaPost & fully generalizes MetaPost path construction algorithms to three-dimensions
Testing plain MetaPost
To test whether MetaPost is installed on your system, create a file called test.mp
:
beginfig(1) draw fullcircle scaled 3cm ; endfig ; end ;
- apply MetaPost on the testfile
mp test.mp or mpost test.mp
- that should create a postscript file test.1
- open test.1 with a postscript viewer like Ghostview, Okular, … You should see a circle.
Testing MetaPost embedded in ConTeXt
If MetaPost is installed on your system and working correctly, you can
\starttext \startMPcode draw fullcircle scaled 3cm; \stopMPcode \stoptext
- for mkii you need to have write18 support enabled and run
texexec --pdf test.tex
- for mkiv run
context test.tex
- that should create a pdf file test.pdf
- open test.pdf with a pdf viewer like Adobe Acrobat, Okular... You should see a circle.
Text in MetaPost
Text that is typeset using textext
or btex … etex
adapts to the body font. However, when label("Foo", pair)
or "Foo" infont defaultfont
is used, which is not the recommended way, the text is typeset using the font MetafunDefault
, which can be changed if desired. Example:
\starttext \startMPcode label("Foo", origin); draw textext("Bar") yshifted -LineHeight; \stopMPcode \definefontsynonym [MetafunDefault] [Bold*default] \switchtobodyfont [pagella, 18pt] \startMPcode label("Foo", origin); draw textext("Foo") yshifted -LineHeight; \stopMPcode \stoptext
Gives:
The recommended way to typeset text is to use the textext
macro and change the font using \setupMPinstance.
Repetition of a Text Element to Fill a Bar Using textext
Imagine you want to create a frame which consists out of one glyph or a combination of different glyphs in order to make a decorative border. For this purpose a series of such elements should be placed on the bar as pictures, evenly spaced. Probably you want to have at the end of the bar a different glyph inserted as a picture too.
The following code is working but the last picture is not the expected glyph. One would expect 14 times the "?" and at the end of the bar a "*":
\starttext \startMPpage picture PicA ; PicA := textext("*"); picture PicB ; PicB := textext("?"); numeric Step ; Step := 2cm div bbwidth(PicB) ; for i = 1 upto Step : draw PicB shifted (i*5mm,0) ; endfor ; draw PicA ; \stopMPpage \stoptext
Gives:
What you get is 15 "?" but no "*"!
In order to get this corrected one needs to calculate the boundingbox of the "?" on beforehand. Hans Hagen provided this solution on 14-10-2014.
\starttext \startMPcalculation path PicX ; PicX := boundingbox textext("?") ; \stopMPcalculation \startMPpage picture PicA ; PicA := textext("*"); picture PicB ; PicB := textext("?"); numeric Step ; Step := 2cm div bbwidth(PicX) ; % numeric Step ; Step := 2cm div bbwidth(PicB) ; for i = 1 upto Step : draw PicB shifted (i*5mm,0) ; endfor ; draw PicA ; \stopMPpage \stoptext
Gives:
Now you get 14 "?" and the "*".
A Full Example
\setupbodyfont[8pt] \defineoverlay[Myframe][\reuseMPgraphic{Frame}] \setuppapersize[A8][A8] \setuplayout [topspace=5mm, backspace=5mm, height=middle, width=middle, header=0pt, footer=0pt] \starttext % ======== Definition of the frame in Metafun ========== \startMPcalculation path PicX ; PicX := boundingbox textext("= : =") ; \stopMPcalculation \startreusableMPgraphic{Frame} numeric u,v,xshift,yshift,picwidth,remnant,nelements; u := OverlayWidth; v := OverlayHeight; path p,w; p := unitsquare xscaled u yscaled v; w := fullcircle scaled 8pt; picture Edgepic,Linepic[]; color edgedotcolor,linelementcolorA; edgedotcolor := blue; linelementcolorA := red; Linepic[1] := textext("\rotate[rotation=90]{= : =}"); Linepic[2] := textext("= : ="); Edgepic := textext("o"); %Calculations for the horizontal frame-element placement: % In order to make this work, the width of the line element needs to be calculated on beforehand. % path PicX; PicX := textext(")("); picwidth := bbwidth(PicX); nelements := u div picwidth; remnant := u mod picwidth; xshift := picwidth + remnant/nelements; Linepic[3] := Linepic[2] shifted (0.5*picwidth,0); for a = llcorner p, ulcorner p : for i = 1 upto nelements : draw Linepic[3] shifted ((xpart a + (i-1)*xshift),ypart a) withcolor linelementcolorA; endfor; endfor; %Calculations for the vertical frame-element placement: picheight := bbwidth(PicX); nelements := v div picheight; remnant := v mod picheight; yshift := picheight + remnant/nelements; Linepic[4]:= Linepic[1] shifted (0,0.5*picheight); for a = llcorner p, lrcorner p : for i = 1 upto nelements: draw Linepic[4] shifted (xpart a,ypart a + (i-1)*yshift) withcolor linelementcolorA; endfor; endfor; for i = llcorner p, lrcorner p,ulcorner p,urcorner p : fill w shifted (xpart i,ypart i) withcolor white; draw Edgepic shifted (xpart i,ypart i) withcolor edgedotcolor; endfor; % For frame-element positioning checking: % draw p; % \stopreusableMPgraphic % ========== \startframedtext [width=0.8\textwidth,height=0.8\textheight,frame=off,background=Myframe, align={middle,lohi}] The butterfly counts not months but moments, and has time enough. \blank {\tfx Rabindranath Tagore} \stopframedtext \stoptext
Gives:
There is some strange cropping going on on the Wiki-implementation. Of course the left frame is in reality equal to the right frame...
There is one important remark: The MPcalculation and the drawing itself must be inside \starttext ... \stoptext.
Other Links
- Metapost home page: http://tug.org/metapost
- John Hobby's page: http://cm.bell-labs.com/who/hobby/MetaPost.html
- Current development: http://foundry.supelec.fr/projects/metapost/
- http://melusine.eu.org/syracuse/metapost/