MetaPost: Drawing for PostScript
The MetaPost system (by John Hobby) implements a picture-drawing language very much like that of MetaFont; the difference is that MetaPost outputs vector graphic files instead of run-length-encoded bitmaps; output formats available are PostScript and SVG.
MetaPost is a powerful language for producing figures for documents to be printed on PostScript printers, either directly or embedded in (La)TeX documents. MetaPost is able to integrate text and mathematics, marked up for use with TeX, within the graphics. Additionally, the PostScript subset created by METAPOST can be interpreted by pdfTEX. So METAPOST figures can be directly included with e. g. the standard graphics
package, while normal EPS images have to be converted first to be usable with pdfLATEX.
(Knuth says that he uses nothing but MetaPost for diagrams in text that he is writing.)
Note: On a Ubuntu distro the package for MetaPost is named texlive-metapost
, with metapost packages in texlive-metapost-doc
, with files in
- automata
- Finite state machines, graphs and trees in MetaPost
- bbcard
- Bullshit bingo, calendar and baseball-score cards
- blockdraw_mp
- Block diagrams and bond graphs, with MetaPost
- bpolynomial
- Drawing polynomial functions of up to order 3
- cmarrows
- MetaPost arrows and braces in the Computer Modern style
- drv
- Derivation trees with MetaPost
- dviincl
- Include a DVI page into MetaPost output
- emp
Encapsulate
MetaPost figures in a document- epsincl
- Include EPS in MetaPost figures
- expressg
- Diagrams consisting of boxes, lines, and annotations
- exteps
- Include EPS figures in MetaPost
- featpost
- MetaPost macros for 3D
- feynmp-auto
- Automatic processing of feynmp graphics
- fiziko
- A MetaPost library for physics textbook illustrations
- garrigues
- MetaPost macros for the reproduction of Garrigues' Easter nomogram
- gmp
- Enable integration between MetaPost pictures and LaTeX
- hatching
- MetaPost macros for hatching interior of closed paths
- latexmp
- Interface for LaTeX-based typesetting in MetaPost
- mcf2graph
- Draw chemical structure diagrams with MetaPost
- metago
- MetaPost output of Go positions
- metaobj
- MetaPost package providing high-level objects
- metaplot
- Plot-manipulation macros for use in MetaPost
- metapost
- A development of Metafont for creating graphics
- metapost-colorbrewer
- An implementation of the colorbrewer2.org colours for MetaPost
- metauml
- MetaPost library for typesetting UML diagrams
- mfpic
- Draw Metafont/post pictures from (La)TeX commands
- mfpic4ode
- Macros to draw direction fields and solutions of ODEs
- minim-hatching
- Create tiling patterns with the minim-mp MetaPost processor
- mp3d
- 3D animations
- mparrows
- MetaPost module with different types of arrow heads
- mpattern
- Patterns in MetaPost
- mpcolornames
- Extend list of predefined colour names for MetaPost
- mpgraphics
- Process and display MetaPost figures inline
- mptrees
- Probability trees with MetaPost
- piechartmp
- Draw pie-charts using MetaPost
- repere
- Diagrams for school mathematics
- roex
- Metafont-PostScript conversions
- roundrect
- MetaPost macros for highly configurable rounded rectangles (optionally with text)
- shapes
- Draw polygons, reentrant stars, and fractions in circles with MetaPost
- slideshow
- Generate slideshow with MetaPost
- splines
- MetaPost macros for drawing cubic spline interpolants
- suanpan
- MetaPost macros for drawing Chinese and Japanese abaci
- textpath
- Setting text along a path with MetaPost
- threeddice
- Create images of dice with one, two, or three faces showing, using MetaPost
Running MetaPost
The basic method for running MetaPost is to create a plain text file with extension .mp and run MetaPost directly on the command line:
mpost ourfile.mp
Inside the .mp
file, the code for drawing the graphics is enclosed within beginfig ... endfig
. The %
character starts a comment. Here's a complete example:
beginfig (1); % draw a line draw (1cm,2cm) -- (3cm,5cm); endfig; end.
The default output from running mpost is a PostScript file, with the file extension being the figure number. With this example, the output would be a file ourfile.1
SVG output; filename extensions
If you add a line outputformat:="svg";
at the very beginning of the file, the output will be in SVG format. However, the resulting file will still be named ourfile.1. Most likely, you will need to rename it to ourfile.svg for it to be recognized. Alternatively, you can tell MetaPost to use .svg
in the first place, like this:
outputtemplate := "%j-%c.svg"; outputformat := "svg";
The %j
is replaced with the main filename and the %c
the figure number, so the output files here would be named ourfile-1.svg, ourfile-2.svg, etc.
You can also have MetaPost use a different extension for its normal PostScript output. Commonly, .mps
is used for this (MetaPost PostScript
), because that extension is already known to (La)TeX and can be handled without any further conversion. Thus:
outputtemplate := "%j-%c.mps";
This will create output files with names like ourfile-1.mps.
Note: For SVG output, converting font glyphs to paths by setting variable prologues to 3 is currently the only reliable way to export text objects to SVG.
Basics
METAPOST defines its own programming language. It consists of the following elements:
- points
- Points are normally named by the letter z and are represented by a pair (x, y).
- pens
- paths
- Paths may contain geometrical elements (e. g.
fullcircle
) or may consist of points that are connected by lines or Bézier curves. - numbers
- colors (originally RGB only; now CMYK is also supported)
- Colors are tuples of three (in case of RGB) or four (in case of CMYK) numbers.
For a short example let's have a look at the following example:
filenametemplate "%j-%3c.mps"; beginfig(1); pickup pencircle scaled 1bp; draw origin--(2cm,1cm) ..(1.3cm,0.3cm)..cycle; endfig; end
As mentioned before, each figure is put between beginfig
and endfig
, with a number identifying the figure. Thus, a METAPOST source may contain several figures. Originally, when processing the source (e. g. ex.mp) with METAPOST (mpost
), the figure numbers were used as file extensions for the resulting PostScript files. In later releases, the command filenametemplate
was introduced, that uses a syntax something like the printf
command in C. In the example above, we would get a PostScript file with the name ex-001.mps (and if we add a figure with number 2, the PostScript output would be written into ex-002.mps).
Since pdfTEX recognizes files with the extension .mps
as METAPOST output, the graphic can be used in a LATEX document with a straight-forward \includegraphics{ex-001.mps}
and the document may be processed either by pdfTEX or, using the original workflow, by compiling to DVI and using dvips.
As in C, all statements may span multiple lines and are finished by the ;
character.
The example figure itself shows a straight line (since two dashes were used in the source) from the origin to the point (2cm, 1cm). Then, the path is closed by a Bézier curve (because two dots were used in the path definition) via the point located at (1.3cm, .3cm). For drawing, a round pen with diameter of one PostScript point is used. METAPOST knows the same units as TEX, like bp for PS points, cm, mm or in.
Comments in MetaPost code are introduced by the percent sign %
, which causes the remainder of the current line to be ignored.
Three assignments
prologues := 3; outputtemplate := "%j-%c.mps"; outputformat := "svg";
If your graphics contain text labels, you might want to set variable prologues to 3 to make sure the correct fonts are used under all possible circumstances. The second assignment changes the output file naming scheme to the form jobname->n.mps. That way, instead of a numeric index, all output files get a uniform file extension mps, which is typically used for MetaPost's PostScript output. The last assignment lets MetaPost write output files in the SVG format rather than in the PostScript format.
Basic Drawing Statements
The simplest drawing statement is the one that draws a single dot with the current pen at a given coordinate:
drawdot (30,0)
MetaPost can also draw straight lines. Thus
draw (20,20)--(0,0)
draws a diagonal line and
draw (20,20)--(0,0)--(0,30)--(30,0)--(0,0)
draws a polygonal line.
MetaPost uses the same names for units of measure that TEX and METAFONT do. Thus bp
refers to PostScript points (big points
) and pt
refers to printer's points. Other units of measure include in
for inches, pc
for picas, cm
for centimeters, mm
for millimeters, cc
for ciceros, and dd
for Didot points.
The coordinate (0,0) can also be referred to as origin
, as in
drawdot origin
Finally, if we substitute dots for hyphens a curve will be drawn instead:
draw (20,20)--(0,0)--(0,30)--(30,0)--(0,0)
Loops
METAPOST offers the usual features of programming languages, like macros, loops and conditional expressions. For illustration I present an example where a path is constructed within a loop:
z0 = 2cm*right; draw origin withpen pencircle scaled 2bp; pickup pencircle scaled 1bp; draw for i:=0 upto 5: z0 rotated (i*60) -- endfor cycle;
The syntax of the for loop uses a variable i that is incremented stepwise from zero until 5. The loop is expanded within the definition of the path to be drawn. Please note that the loop is ended by endfor
without a semicolon. If a semicolon were present, it would be interpreted as end of the draw statement, leading to a syntax error.
Equations and Coordinate Pairs
MetaPost can also solve linear equations involving coordinate pairs. We have already seen many trivial examples of this in the form of equations like
z1=(0,.2in)
Each side of the equation must be formed by adding or subtracting coordinate pairs and multiplying or dividing them by known numeric quantities. Other ways of naming pair-valued variables will be discussed later, but the znumber is convenient because it is an abbreviation for
(xnumber, ynumber)
This makes it possible to give values to z variables by giving equations involving their coordinates. For instance, points z1, z2, z3, and z6 are initialized via the following equations:
z1=-z2=(.2in,0); x3=-x6=.3in; x3+y3=x6+y6=1.1in;
An interpolation follows the k[z0, z1]
syntax, as in
beginfig(13); z1=-z2=(.2in,0); x3=-x6=.3in; x3+y3=x6+y6=1.1in; z4=1/3[z3,z6]; z5=2/3[z3,z6]; z20=whatever[z1,z3]=whatever[z2,z4]; z30=whatever[z1,z4]=whatever[z2,z5]; z40=whatever[z1,z5]=whatever[z2,z6]; draw z1--z20--z2--z30--z1--z40--z2; pickup pencircle scaled 1pt; draw z1--z2; draw z3--z6; endfig;
The macro whatever
generates a new anonymous variable each time it appears. Thus the statement
z20=whatever[z1,z3]=whatever[z2,z4]
sets z20 as before, except it uses whatever to generate two different anonymous variables instead of aa and ab.
Expressions
Data Types
MetaPost actually has ten basic data types: numeric, pair, path, transform, (rgb)color, cmykcolor, string, boolean, picture, and pen. Let us consider these one at a time beginning with the numeric type.
Numeric quantities in MetaPost are represented in fixed point arithmetic as integer multiples of 1 / 65536, the smallest positive value, which is also available as the predefined constant epsilon
. Numeric quantities must normally have absolute values less than 4096 but intermediate results can be eight times larger. This should not be a problem for distances or coordinate values since 4096 PostScript points is more than 1.4 meters. If you need to work with numbers of magnitude 4096 or more, setting the internal variable warningcheck
to zero suppresses the warning messages about large numeric quantities.
The pair type is represented as a pair of numeric quantities. We have seen that pairs are used to give coordinates in draw statements. Pairs can be added, subtracted, used in mediation expressions, or multiplied or divided by numerics.
Paths have already been discussed in the context of draw statements, but that discussion did not mention that paths are first-class objects that can be stored and manipulated. A path represents a straight or curved line that is defined parametrically.
Another data type represents an arbitrary affine transformation. A transform can be any combination of rotating, scaling, slanting, and shifting. If p = (px , py ) is a pair and T is a transform, then
p transformed T
is a pair of the form
(tx + txx px + txy py , ty + tyx px + tyy py),
where the six numeric quantities (tx, ty, txx, txy, tyx, tyy) determine T.
Transforms can also be applied to paths, pictures, pens, and transforms.
The color type is like the pair type, except that it has three components instead of two and each component is normally between 0 and 1. Like pairs, colors can be added, subtracted, used in mediation expressions, or multiplied or divided by numerics. Colors can be specified in terms of the predefined constants black
, white
, red
, green
, blue
, or the red, green, and blue components can be given explicitly. Black is (0,0,0) and white is (1,1,1). A level of gray such as (.4,.4,.4) can also be specified as 0.4white
. Although color typed variables may be any ordered triplet, when adding an object to a picture, MetaPost will convert its color by clipping each component between 0 and 1. For example, MetaPost will output the color (1,2,3) as (1,1,1). MetaPost solves linear equations involving colors the same way it does for pairs. The type 'rgbcolor' is an alias of type 'color'.
The cmykcolor type is similar to the color type except that it has four components instead of three. This type is used to specify colors by their cyan, magenta, yellow, and black components explicitly. Because CMYK colors deal with pigments instead of light rays, the color white would be expressed as (0,0,0,0) and black as (0,0,0,1). In theory, the colors (c,m,y,1) and (1,1,1,k) should result in black for any values of c, m, y and k, too. But in practice, this is avoided since it is a waste of colored ink and can lead to unsatisfactory results.
A string represents a sequence of characters. String constants are given in double quotes "like this". String constants cannot contain double quotes or newlines, but there is a way to construct a string containing any sequence of eight-bit characters.
Conversion from strings to other types, notably numeric, can be accomplished by the scantokens
primitive:
n := scantokens(str);
More generally, scantokens parses a string into a token sequence, as if MetaPost had read it as input.
The boolean type has the constants true and false and the operators and, or, not. The relations = and <> test objects of any type for equality and inequality. Comparison relations <, <=, >, and >= are defined lexicographically for strings and in the obvious way for numerics. Ordering relations are also defined for booleans, pairs, colors, and transforms, but the comparison rules are not worth discussing here.
The picture data type is just what the name implies. Anything that can be drawn in MetaPost can be stored in a picture variable. In fact, the draw
statement actually stores its results in a special picture variable called currentpicture
. Pictures can be added to other pictures and operated on by transforms.
Finally, there is a data type called a pen. The main function of pens in MetaPost is to determine line thickness, but they can also be used to achieve calligraphic effects. The statement
pickup pen expression
causes the given pen to be used in subsequent draw
or drawdot
statements. Normally, the pen expression is of the form
pencircle scaled numeric primary
The statement above defines a circular pen that produces lines of constant thickness. If calligraphic effects are desired, the pen expression can be adjusted to give an elliptical pen or a polygonal pen.
Operators
There are many different ways to make expressions of the ten basic types, but most of the operations fit into a fairly simple syntax with four levels of precedence as shown below. There are primaries, secondaries, tertiaries, and expressions of each of the basic types, so the syntax rules could be specialized to deal with items such as numeric primary, boolean tertiary, etc. This allows the result type for an operation to depend on the choice of operator and the types of its operands. For example, the <
relation is a tertiary binary that can be applied to a numeric expression and a numeric tertiary to give a boolean expression. The same operator can accept other operand types such as string expression and string tertiary, but an error message results if the operand types do not match.
primary → variable | (expression) | nullary op | of operatorexpressionofprimary | unary opprimary secondary → primary | secondaryprimary binopprimary tertiary → secondary | tertiarysecondary binopsecondary expression → tertiary | expressiontertiary binoptertiary
The multiplication and division operators * and / are examples of what the synopsis above calls a primary binop. Each can accept two numeric operands or one numeric operand and one operand of type pair or color. The exponentiation operator **
is a primary binop that requires two numeric operands. Placing this at the same level of precedence as multiplication and division has the unfortunate consequence that 3*a**2 means (3a)2 , not 3(a2). Since unary negation applies at the primary level, it also turns out that -a**2 means (−a)2. Fortunately, subtraction has lower precedence so that a-b**2 does mean a − (b2) instead of (a − b)2.
Another primary binop is the dotprod
operator that computes the vector dot product of two pairs. For example, z1 dotprod z2
is equivalent to x1*x2 + y1*y2.
The additive operators + and - are secondary binops that operate on numerics, pairs, or colors and produce results of the same type. Other operators that fall in this category are Pythagorean addition ++ and Pythagorean subtraction +-+: a++b
means a2 + b2 and a+-+b
means a2 − b2.
There are too many other operators to list here, but some of the most important are the boolean operators and
and or
. The and
operator is a primary binop and the or
operator is a secondary binop.
The basic operations on strings are concatenation, substring construction and calculating the length of a string. The tertiary binop &
implements concatenation; e.g.,
"abc" & "de"
produces the string "abcde". The length
operator returns the number of characters in a string if the argument is a string primary; e.g.,
length "abcde"
returns 5. For substring construction, the of operator substring
is used like this:
substring pair expression of string primary
The pair expression determines what part of the string to select. For this purpose, the string is indexed so that integer positions fall between characters. Pretend the string is written on a piece of graph paper so that the first character occupies x coordinates between zero and one and the next character covers the range 1 ≤ x ≤ 2, etc. and substring (2,4) of "abcde"
is "cd". This takes a little getting used to but it tends to avoid annoying off by one
errors.
Some operators take no arguments at all. An example of what above is called a nullary op is nullpicture
, which returns a completely blank picture.
The basic syntax in the synopsis above only covers aspects of the expression syntax that are relatively type-independent.
Fractions, Mediation, and Unary Operators
Mediation expressions do not appear in the basic expression syntax above. Mediation expressions are parsed at the primary level, so the general rule for constructing them is
primary → numeric atom[expression,expression]
where each expression can be of type numeric, pair, or color. The numeric atom in a mediation expression is an extra simple type of numeric primary as shown below. The meaning of all this is that the initial parameter in a mediation expression needs to be parenthesized when it is not just a variable, a positive number, or a positive fraction. For example,
-1[a,b]
and
(-1)[a,b]
are very different: the former is −b since it is equivalent to -(1[a,b]); the latter is a − (b − a) or 2a − b.
numeric primary → numeric atom | numeric atom[numeric expression,numeric expression] | of operatorexpressionofprimary | unary opprimary numeric atom → numeric variable | number or fraction | (numeric expression) | numeric nullary op number or fraction → number/number | number not followed by ‘/number’
A noteworthy feature of the syntax rules above is that the / operator binds most tightly when its operands are numbers. Thus 2/3 is a numeric atom while (1+1)/3 is only a numeric secondary. Applying a unary op such as sqrt
makes the difference clear:
sqrt 2/3
means square root of (2/3), while
sqrt(1+1)/3
means (square root of 2) / 3
. Operators such as sqrt
can be written in standard functional notation, but it is often unnecessary to parenthesize the argument. This applies to any function that is parsed as a unary op. For instance abs(x) and abs x both compute the absolute value of x. The same holds for the round, floor, ceiling, sind, and cosd functions. The last two of these compute trigonometric functions of angles in degrees.
Not all unary operators take numeric arguments and return numeric results. For instance, the abs
operator can be applied to a pair to compute the Euclidean length of a vector. Applying the unitvector
operator to a pair produces the same pair rescaled so that its Euclidean length is 1. The decimal
operator takes a number and returns the string representation. The angle
operator takes a pair and computes the two-argument arctangent; i.e., angle
is the inverse of the dir
operator discussed elsewhere. There is also an operator cycle
that takes a path primary and returns a boolean result indicating whether the path is a closed curve.
There is a whole class of other operators that classify expressions and return boolean results. A type name such as pair can operate on any type of primary and return a boolean result indicating whether the argument is a pair. Similarly, each of the following can be used as a unary operator: numeric
, boolean
, cmykcolor
, color
, string
, transform
, path
, pen
, picture
, and rgbcolor
. Besides just testing the type of a primary, you can use the known and unknown operators to test if it has a completely known value.
Even a number can behave like an operator in some contexts. This refers to the trick that allows 3x
and 3cm
as alternatives to 3*x
and 3*cm
. The rule is that a number or fraction that is not followed by +, -, or another number or fraction can serve as a primary binop. Thus 2/3x
is two thirds of x and 3 3
is illegal.
There are also operators for extracting numeric subfields from pairs, colors, cmykcolors, and even transforms. If p is a pair primary, xpart p
and ypart p
extract its components so that (xpart p, ypart p)
is equivalent to p even if p is an unknown pair that is being used in a linear equation. Similarly, a color c
is equivalent to (redpart c, greenpart c, bluepart c)
. For a cmykcolor c, the components are (cyanpart c, magentapart c, yellowpart c, blackpart c)
and for a greyscale color c
, there is only one component greypart c
.
Variables
MetaPost allows compound variable names such as z.a, x2r, y2r, and z2r, where z2r means (x2r,y2r) and z.a means (x.a,y.a). In fact there is a broad class of suffixes such that zsuffix
means (xsuffix, ysuffix).
Since a suffix is composed of tokens, it is best to begin with a few comments about tokens.
Tokens
A MetaPost input file is treated as a sequence of numbers, string constants, and symbolic tokens. A number consists of a sequence of digits possibly containing a decimal point. Technically, the minus sign in front of a negative number is a separate token. Since MetaPost uses fixed point arithmetic, it does not understand exponential notation such as 6.02E23
. MetaPost would interpret this as the number 6.02, followed by the symbolic token E, followed by the number 23.
Anything between a pair of double quotes (") is a string constant. It is illegal for a string constant to start on one line and end on a later line. Nor can a string constant contain double quotes (") or anything other than printable ASCII characters.
Everything in a line of input other than numbers and string constants is broken into symbolic tokens. A symbolic token is a sequence of one or more similar characters, where characters are similar
if they occur on the same row of the table.
Thus A_alpha
and +-+
are symbolic tokens but !=
is interpreted as two tokens and x34
is a symbolic token followed by a number. Since the brackets [ and ] are listed on lines by themselves, the only symbolic tokens involving them are [, [[, [[[, etc. and ], ]], etc.
Some characters are not listed in the table because they need special treatment. The four characters ,;() are loners
: each comma, semicolon, or parenthesis is a separate token even when they occur consecutively. Thus (()) is four tokens, not one or two. The percent sign is very special because it introduces comments. The percent sign and everything after it up to the end of the line are ignored.
Another special character is the period. Two or more periods together form a symbolic token, but a single period is ignored, and a period preceded or followed by digits is part of a number Thus ..
and ...
are symbolic tokens while a.b
is just two tokens a and b. It is conventional to use periods to separate tokens in this fashion when naming a variable that is more than one token long.
ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz |
:<=>| |
#&@$ |
/*\ |
+- |
!? |
’‘ |
^~ |
{} |
[ |
] |
Variable Declarations
A variable name is a symbolic token or a sequence of symbolic tokens. Most symbolic tokens are legitimate variable names, but anything with a predefined meaning like draw, +, or .. is disallowed; i.e., variable names cannot be macros or MetaPost primitives. This minor restriction allows an amazingly broad class of variable names: alpha
, ==>
, @&#$&
, and ~~
are all legitimate variable names. Such symbolic tokens without special meanings are called tags.
A variable name can be a sequence of tags like f.bot
or f.top
. The idea is to provide some of the functionality of Pascal records or C structures. It is also possible to simulate arrays by using variable names that contain numbers as well as symbolic tokens. For example, the variable name x2r
consists of the tag x
, the number 2, and the tag r
. There can also be variables named x3r
and even x3.14r
. These variables can be treated as an array via constructions like x[i]r
, where i has an appropriate numeric value. The overall syntax for variable names is shown below.
variable → tagsuffix suffix → empty | suffixsubscript | suffixtag subscript → number | [numeric expression]
Variables like x2 and y2 take on numeric values by default, so we can use the fact that zsuffix
is an abbreviation for (xsuffix, ysuffix)
to generate pair-valued variables when needed. It turns out that the beginfig
macro wipes out pre-existing values variables that begin with the tags x or y so that beginfig . . . endfig
blocks do not interfere with each other when this naming scheme is used. In other words, variables that start with x, y, z are local to the figure they are used in.
Type declarations make it possible to use almost any naming scheme while still wiping out any previous value that might cause interference. For example, the declaration
pair pp, a.b;
makes pp and a.b unknown pairs. Such a declaration is not strictly local since pp and a.b are not automatically restored to their previous values at the end of the current figure. Of course, they are restored to unknown pairs if the declaration is repeated.
Declarations work the same way for any of the other nine types: numeric, path, transform, color, cmykcolor, string, boolean, picture, and pen. The only restriction is that you cannot give explicit numeric subscripts in a variable declaration. Do not give the illegal declaration
numeric q1, q2, q3;
use the generic subscript symbol [] instead, to declare the whole array:
numeric q[];
You can also declare multidimensional
arrays. After the declaration
path p[]q[], pq[][];
p2q3 and pq1.4 5 are both paths.
Internal variables like tracingonline
cannot be declared in the normal fashion. All the internal variables discussed in this manual are predefined and do not have to be declared at all, but there is a way to declare that a variable should behave like a newly-created internal variable. The declaration is newinternal
followed by an optional type specifier numeric or string and a list of symbolic tokens. For example,
newinternal numeric n, m; newinternal string s, t; newinternal num;
are valid declarations that declare three internal numeric variables n, m, and num and two internal string variables s and t.
Internal variables always have known values, and these values can only be changed by using the assignment operator :=
. Internal numeric variables are initially zero and internal string variables are initially the empty string ""
, except that the Plain macro package gives some of the variables different initial values.
Internal string variables have been introduced in MetaPost version 1.200. For backwards compatibility, if the type specifier is missing, internal variables default to a numeric type, as in the last example. The declarations newinternal numeric;
and newinternal string;
are invalid and throw an error.
Transformations of paths
METAPOST supports the following transformations of paths:
- Translations
p0 shifted (x1, x2)
- Rotation
p0 rotated alpha
- Scaling (in both directions, or in x or y direction individually)
p0 scaled factor p0 xscaled xfactor p0 yscaled yfactor
- Slanting
p0 slanted alpha
Text and labels
METAPOST supports placing labels into a figure. In the simplest form, the text may be included directly, without any typesetting done by TEX:
defaultfont := "ptmr8r"; defaultscale := 1.2; label("this is a label",z0);
It will just add the text commands to write the label text in 12pt Times Roman (a font scaling factor of one refers to 10pt) into the PostScript code. Note that :=
is used in the code above, since new values are assigned to the variables, while = is used in linear equations (equality).
The action of placing a label at z0 in the example is rather straightforward. The label command centers the label at the given point. In many cases, a suffix is appended to the label command to define how the label is placed in relation to the given point, i. e. top
, bot
(bottom), lft
(left), rt
(right) or ulft
, llft
, urt
, lrt
(e. g. ulft
means upper left and lrt
means lower right). The label command may be replaced by dotlabel
, that draws a dot at the given point in addition to the label. For example, the code
dotlabel.urt("this is a label",z0)
draws a dot at z0 and places the given text in upper right direction from z0.
Labels in TeX
Only simple text may be used for labels that are included by METAPOST directly. But for real typesetting, we may use one of the best typesetting programs we know, TEX itself. We may include nearly arbitrary TEX stuff into labels. All TEX snippets that occur in the METAPOST source are extracted and typeset with TEX, before the result is included into the figure by METAPOST.
All the TEX stuff has to be embedded into an environment btex ... etex
, e. g.
label(btex $z_0$ etex, z0)
will center the label z0
at this point. Normally, the plain TEX compiler is used for typesetting the btex ... etex
fragments. But the name of the program may be passed on the command line when calling METAPOST, so to use LATEX we can give the command
mpost --tex=latex ex1
Let's have a look how we can typeset a label with LATEX, using Euler math fonts to typeset a formula:
filenametemplate "%j-%3c.mps"; verbatimtex \documentclass{article} \usepackage{euler} \begin{document} etex beginfig(1); dotlabel.urt( btex $\sqrt{\frac{1}{1+x^2}}$ etex, origin); endfig;
Since typesetting with LATEX requires a preamble loading a document class and maybe some extra packages, the example contains an environment
verbatimtex ... etex
which is included as verbatim code before typesetting all the labels. In this example, we load the article
class and the euler
package. While we had to explicitly write the \begin{document}
, the closing \end{document}
is inserted automatically!
Including labels causes some difficulties with fonts. Normally, METAPOST doesn't embed fonts but just adds a reference to the used fonts into the PostScript output. This isn't a problem when METAPOST is included in a TEX document, since TEX will resolve all of these font references. But the figures won't be usable standalone, since PostScript interpreters like Ghostscript will complain about un- known fonts.
In recent versions of METAPOST it is possible to run METAPOST in a mode that will produce standalone PostScript output that contains a real
EPS with all fonts embedded, that can be displayed in any PS interpreter or may be used in other applications besides TEX documents.
A switch named prologues defines whether METAPOST will embed fonts or not. The definition prologues:=3;
at the start of your METAPOST file will produce a standalone EPS figure. The default value of prologues is 0, which means that no fonts will be embedded. The meaning of other values of prologues may be looked up in the METAPOST manual; they are relevant only for special cases.
The infont Operator
Regardless of whether you use TEX or troff, all the real work of adding text to pictures is done by a MetaPost primitive operator called infont
. It is a primary binop that takes a string secondary as its left argument and a string primary as its right argument. The left argument is text, and the right argument is a font name. The result of the operation is a picture secondary, which can then be transformed in various ways. One possibility is enlargement by a given factor via the syntax
picture secondary scaled numeric primary
Thus label("text",z0)
is equivalent to
label("text" infont defaultfont scaled defaultscale, z0)
If it is not convenient to use a string constant for the left argument of infont, you can use char numeric primary to select a character based on its numeric position in the font. Thus
char(n+64) infont "ptmr8r"
is a picture containing character n+64 of the font ptmr8r, which is a typical TEX way to refer to Times-Roman.
Bare MetaPost does not do any kind of input reencoding, so when you use infont
string for labels (instead of btex . . . etex
), the string has to be specified in the font encoding.
Measuring Text
MetaPost makes readily available the physical dimensions of pictures generated by the infont
operator. There are unary operators llcorner
, lrcorner
, urcorner
, ulcorner
, and center
that take a picture primary and return the corners of its bounding box.
The center
operator also accepts path primary and pen primary operands. In MetaPost Version 0.30 and higher, llcorner
, lrcorner
, etc. accept all three argument types as well.
The argument type restrictions on the corner operators are not very important because their main purpose is to allow label and dotlabel statements to center their text properly. The predefined macro
bbox picture primary
finds a rectangular path that represents the bounding box of a given picture. If p is a picture, bbox p
is equivalent to
(llcorner p--lrcorner p--urcorner p--ulcorner p--cycle)
except that it allows for a small amount of extra space around p as specified by the internal variable bboxmargin
.
Note that MetaPost computes the bounding box of a btex . . . etex
picture just the way TEX does. This is quite natural, but it has certain implications in view of the fact that TEX has features like \strut
and \rlap
that allow TEX users to lie about the dimensions of a box.
When TEX commands that lie about the dimensions of a box are translated in to low-level MetaPost code, a setbounds
statement does the lying:
setbounds picture variable to path expression
makes the picture variable behave as if its bounding box were the same as the given path. The path has to be a cycle, i.e., it must be a closed path. To get the true bounding box of such a picture, assign a positive value to the internal variable truecorners
: i.e.,
show urcorner btex $\bullet$\rlap{ A} etex
produces >> (4.9813,6.8078)
while
truecorners:=1; show urcorner btex $\bullet$\rlap{ A} etex
produces "" (15.7742,6.8078).
Time variables
A path in METAPOST may be imagined as the travel of a vehicle. Paths are parameterized by a time variable (which might be a bit misleading, since of course the drawing is static). So a path has a start and end time, and any point is correlated to a time in between (and vice versa).
Here is an example where time variables are used:
pickup pencircle scaled 1bp; path p[]; p0 = origin{up}..(3cm,2cm); p1 = (-5mm,2cm)--(3cm,5mm); draw p0 dashed withdots; draw p1 dashed withdots; (t0,t1) = p0 intersectiontimes p1; draw subpath (0,t0) of p0 -- subpath (t1,length(p1)) of p1;
We have two paths, p0 and p1: a Bézier curve from lower left to upper right, and a straight line from upper left to lower right, drawn with dotted lines.
To combine the subpath of p0 before the intersection point with the subpath of p1 after this point, as drawn with a solid line in fig. 5, it is not sufficient just to know the intersection point ot p0 and p1.
In this case, we need the time values of both paths in the intersection point. For this, the statement p0 intersectiontimes p1 is used. The result of this is a pair (thus a point), with the time value of p0 in the intersection point as the first part (x-part) and the time value of p1 as the second part (y-part).
As soon as these time values are known, the desired path is constructed using subpath. This is a perfect example showing that METAPOST as a standalone program has full control over the paths, contrary to other tools like PSTricks that let PostScript do the job of drawing the paths.