Prev Up Top Next Contents
7.A MetaPost
This appendix describes the most important MetaPost commands
[
13] .
MethaPost files are text files, like therion or survex files, with
commands for MetaPost
, just like therion files contain
commands for therion
and survex files contain commands for
survex
.
To work with metapost is therefore enough to write text file
(with extension ".mp" by default) and input them to mpost
.
The outcome are little PostScript files that can be viewed
with any PostScript viewer (for example, with ghostscript
).
Any command is terminated by ';'.
The character '%' starts a comment. The comment continues till the
end of the line.
The
metapost
commands specify how to draw the figure(s),
therefore they are mostly related to line drawing.
MetaPost has nine data types:
- numeric, numerical values;
- pair, pair of (x,y) coordinates for points in the plane
of the drawing;
- path, the lines that make the drawing;
- color, colors used to draw the figure;
- string, text written in the figure;
- picture, pieces of the figure, ie, what is drawn;
- pen, the pen used to draw lines;
before you use a pen, you must pick it up (eg, pickup pensquare");
- transform, affine transformations: they can be applied to path,
picture, string and pen to rotate, scale, etc.
- boolean, a variable that can be either "true" or "false".
In MetaPost you can define arrays, for instance "path p[];"
and then refer to its elements as "p0", "p1" etc.
Index with decimal part are allowed: "p1.2".
The elements of an array can be indexed with subscript too: "p.a".
Multidimensional array are supported: "path p[]q[], rs[][];".
An element of the first could be "p2q3", one of the second "rs1 5".
7.A.1 Boolean
A boolean variable may be used as parameter in a function to determine
its behaviour. For example
% warning is called with filled=true, p must be a cycle
vardef draw_or_fill(expr p, filled) =
if filled: fill p else: draw p fi
enddef;
7.A.2 Pens
MetaPost has a few predefined pens: pencircle", "pensquare", and
"penrazor". The variable "currentpen" refers to the pen in use.
The variable "defaultpen" is the default pen.
The operator "makepen" takes as parameter a path and produces a pen,
with shape the convex hull of the path. The inverse operator is
"makepath" that, given a pen, produces the path contour of the pen.
The composition of the two operators is the convex hull of the path.
7.A.3 Colors
A color is composed of three numbers (red, green, and blue) betweeen 0
and 1. There are also predefined colors that can be referred to by the name:
"black", "white", "red", "green" and "blue".
A grey color can be defined as a fraction of the white: "0.4 white".
To get the components of a color there are the operators
"redpart", "greenpart" and "bluepart".
7.A.4 Trasformations
A transformation has six parameters
X' = tx + txx X + txy Y
Y' = ty + tyx X + tyy Y
The transformations are applied in the order they are read, from the left
to the right. For instance
p rotated R shifted S; says that the path "p"
is first rotated by "R" then trasnlated by "S".
The transformations can be composed to form new (complex) ones.
A particular transformation is the "identity".
A roto-translation can be defined as
transform T; T = identity rotated 60 shifted (2.0, 3.0);
There are a few operators that define transformations:
- "shifted (a,b)": takes (x,y) in (x+a, y+b);
- "rotated t": takes (x,y) in ( x cos(t) - y sin(t), x sin(t) + y cos(t) );
- "slanted a": takes (x,y) in (x+ay, y);
- "scaled a": takes (x,y) in (ax, ay);
- "xscaled a": takes (x,y) in (ax, y);
- "yscaled a": takes (x,y) in (x, ay);
- "zscaled (a,b)": takes (x,y) in (ax - by, bx + ay);
- "reflectedabout (p,q)": reflects about the p-q line;
- "rotatedaround (p,t)": rotates by an angle "t" around the point "p".
If "T" is a transformation, "inverse T" is its inverse transformation.
To get the individual parameters of a transformation there are the operators
"xpart", "xxpart", "xypart", etc.
Finally it is possible to define a transformation specifying how it acts on
three points, ie, with a system of three linear equations.
7.A.5 Numbers and points
Points and lines must be expressed with a units.
If it is not specified, MetaPost uses typographics points
(1/72 inch). One can use cm, mm, ... or a unit "u" can be defined, as
therion
does, and everything can be expressed in terms of "u".
A point is a pair (x,y) of coordinates.
MetaPost has a convention to
refer to the points: pairs of coordinates have name with prefix "z";
their x and y components have names with prefixes "x" and "y", respecively.
For example,
z1:=(1.2u, 0.5u);
implies that "x1" is 1.2u and "y1" is 0.5u.
Numbers and points can be defined through a system of linear equations.
This is convenient for geometric drawings to refer to points of intersection
of lines. For example
z0 = 1/3[z1,z2];
defines the point Z0 = (2 Z1 + Z2)/3. Another example,
a + b = 3;
a - b = 1;
defines "a" and "b" through a system of two linear equations ("a" is 2, "b" is
1).
The operators "xpart" and ypart" refer to the components of a point.
A 2D vector is represented as a pair.
The operator "unitvector" applied to a pair, produces the unit
length vector in the direction of the pair.
The operator "lft", "rt", "top" and "bot" applied to a pair
produce the left, right, upper and lower coordinates, respectively.
7.A.6 Lines
There are three main ways to define the piece of a path between
two points, "z1" and "z2",
- as a straight segment, with two dashes: z1 -- z2
- as a (cubic) curve, with two dots: z1 .. z2
- as a curve, without inflection points, with three dots,
z1 ... z2
Furthermore the last point of a path can be defined with the keyword "cycle"
which states to close the path on the first point. For example,
a square at 45 degrees,
p := (-u,0) -- (0,u) -- (u,0) -- (0-u) -- cycle;
Several operators controls the curvature of a curved line.
One can define the "tension" in the segment (even asymmetrically),
the endpoints curvature, and the direction (the tangent) at the endpoints.
The most important way is however through the control points.
Each point of a line can have two control points, a forward one and a backward
one. Therion uses this method. The curve between Z1 and Z2 depends on the two
points Z1" (to the right of Z1) and Z2' (to the left of Z2) as follows
Z(t) = t3 Z1 + 3 t2 (1-t) Z1" + 3 t (1-t)2 Z2' + (1-t)3 Z2
When Z1"=Z1 and Z2'=Z2 this equation becomes the straight segment Z1-Z2.
Once you have defined a line, you can draw it using one of these operators.
- "draw p" draws the line "p" using the current pen;
- "fill p" colors the area enclosed by "p";
- "filldraw p", is the composition of the two preceeding operations;
- "undraw p" draws "p" using the backgroung color, ie, erases "p";
- "unfill p" erases the area enclosed by "p".
- "unfilldraw p".
Every draw/fill operation covers what has already been drawn.
For example "undraw" is an effective erase, as it draws with the background
color. Therefore it is important to write the drawing operators in the correct
order, to avoid having a piece of the drawing hidden behind another.
The function "drawoptions" changes the global drawing settings:
drawoptions(withcolor O.5[black, white]); % set the color grey
drawoptions(dashed evenly);
drawoptions(withpen pensquare scaled 0.4); % set the pen
To set two or more settings write all of them in a row, separated
by spaces in a single call to "drawoptions()". For example
drawoptions(withpen pencircle scaled 0.4 dashed evenly);
.
It is possible to specify which pen to use, "withpen q", and which color,
"withcolor c".
To draw arrows one has the functions "drawarrow" and "drawdblarrow".
The size of the arrow head depends on the variables "ahlength" (length) and
"ahangle" (angle at the arrow head).
Dashed lines are drawn using the option "dashed" followed by the dash pattern,
draw p dashed pattern;
A pattern is a
picture without texts and "fill" operations.
There are two predefined patterns, "evenly" and "withdots".
Being pictures, the patterns can be transformed (for example "scaled").
Finally the function "dashpattern" allows to define a patters specifying a
list of "on"/"off".
The variable "linecap" determines the ending of the lines.
By default it is "rounded", but it can be "squared" or "butt".
The variable "linejoin" determines how to draw the line corners.
By default it is "rounded", but it can be "beveled" (a polygon) or
"mitered" (pointed).
To get informations about the position of a line there are the operators
"llcorner, "lrcorner", etc. (for the bounding box corners) and "bbox"
for the bounding box (with a small extra margin, "bboxmargin").
These operators can be applied also to picture and pen.
A special operator is "buildcycle". Applied to a sequence of paths
it finds a close line (a cycle) joining the pieces of the paths
delimited by the intersections of the path with the previous and the
next ones. The result depends on the number of intersections of the paths.
Roughly MetaPost trys to find the intersections that maximize the length
of these pieces; however the algorithm is more complex, and in case of
multiple intersections the result could not be what expected.
The operators "precontrol" and "postcontrol" give the control points of a
path. For example "precontrol 2 of p" gives the precontrol point of the third
point on the path (indices start at 0).
The drawing functions are implemented through the function "addto" which
adds a graphical element (picture, path, or contour) to a picture.
7.A.7 Text
The following functions create objects of
string type, ie, text:
- "label(s, p)" draws a string, with value (text) "s" at the point "p";
- "dotlabel(s, p)" is similar but it draws also a circular dot in "p";
- "thelabel(s, p)" creates the path that can be used to draw the string.
This function is used to get the bounding box of a label and erase the
drawing before writing the string, so that the label is more readable.
These operators can have also, as suffix, the position of the text with
respect to the point: "lft" (left), "rt" (right), "llft", "ulft", "lrt" and
"urt". The distance of the text from the point is determined by the global
variable "labeloffset".
The variables "defaultfont" and "defaultscale" define the font for the texts.
For example,
defaultfont := "Times-Roman";
defaultscale := 10 pt;
label("My text", z0);
The "fontsize" operator returns the size of the font.
If the text has formatting commands and must be processed by TeX, it must be
delimted by "btex" and "etex". This is useful to write math formulas in the
drawing The "btex"/"etex" block is a
picture; it can be rotated, etc.
To include a piece of TeX at the beginning of the file, you use
"verbatimtex" (teminated by "etex"). For example (cyrillic fonts)
verbatimtex
\font\cyr=wncyr10
etex
7.A.8 Picture
The "currentpicture" variable refers to the current picture.
Predefined pictures are "fillcircle", a filled circle, and "halfcircle",
the semicircle with positive y.
The "clip" function clips a picture to the region inside a path.
For example "clip picture to path;".
7.A.9 Operations
The assignment operator ":=" assigns the value of the expression on the right
hand side to the variable on the left hand side. For example "bboxmargin:=5"
sets the margin of the bounding-box to 5 pt.
The equal sign. "=" defines an equation, and can be used to define the value
of a variable.
MetaPost can do arithmetics (sum, product, etc. even exponentiation),
logical operations ("and", "or"), math functions ("sqrt", "abs", etc.).
In particular for points there is the scalar product "dotprod", and for
numbers the pythagoric sum and difference,
"a++b" = (a2 + b2)1/2,
"a+-+b" = (a2 - b2)1/2.
"angle p" is the inverse tangent (arctan) of the (x,y) pair of "p".
Strings have the concatenation operation, "s1 & s2", and the substring extraction,
"substring (a,b) of s". The operator "decimal" applied to a number produces
its string expression.
MetaPost uses the curvilinear coordinate to describe every curve
mathematically. This varies between 0 and N, the number of points of the line,
and it is cyclically repeated if the line is close.
MetaPost has sevral
path operations:
- "p1 intersection p2" gives the point of intersection of "p1" and "p2";
- "p1 intersectiontimes p2" gives the pair of curvilinear coordinates of the
two paths, that correspond to the intersection point;
- "point t of p" is the point with coordinate "t" on the path "p";
- "length p" is the length of the path "p" (curvilinear coordinate);
- "subpath(t1,t2) of p" is the portion of "p" between two coordinates;
- "p1 cutbefore p2" is the portion of "p1" after the intersection with "p2";
- "p1 cutafter p2" is the portion of "p1" before the intersection with "p2";
- "direction t of p" is the tangent vector at "p" in the point of coordinate
"t";
- "directiontime v of p" is the coordinate on "p" where the tangent is "v";
- "directionpoint v of p" is the point of "p" where the tangent is "v";
- "arclength p" is the arclength of "p";
- "arctime a of p" is the coordinate on "p" at the point od arclength "a".
The rules of precedence and composition of the operators are important to
understand some
MetaPost
errors.
MetaPost
has six categories of objects. These are, roughly,
- atom: numbers, variables, expressions in parenthesis,
begingroup/endgroup blocks, btex/etex blocks
- primary: an atom,
the result of a unary operator applied to a primary,
the result of an interpolation (square brackets),
the result of an operator with "of",
the variables "str" and "z" with a suffix.
- secondary: a primary, or the result of a primary binary operator applied
to a secondary and a primary;
- terziary: a secondary, or the result of a secondary binary operator
applied to a terziary and a secondary;
- subexpression: a terziary, or the result of a path-join ("--", "..",etc.)
- expression: a subexpression, or the result of a terziary binary operator
applied to an expression and a terziary.
The operators are subdivided in categories:
- nullary: for example, "true", "false", "whatever";
- unary: with one argument, like the mathematical functions;
- type operators, that define a variable as of a given type;
- binary: with two arguments:
- primary: *, /, **, and, dotprod, div, mod, infont ;
- secondary: +, -, ++, +-+ , and the intersection operators;
- terziary: &, = , and the operators of cut and comparison;
- "of" operators that have an argument preceeded by "of".
7.A.10 Control structures
MetaPost
has the main control structures of a programming language:
"for" loops, and "if" conditionals.
These can be mixed in the definition of a path.
To check if a symbol is defined use the keyword "known": for example
if known ATTR_name:
The syntax of the "for" loop is
for i=0 step S until N:
...
endfor
There is also "for i=0 upto N: ..." where "upto" is equivalen to
"step 1 until".
Other loops:
- with the list of values: "for i=v1, v2, v3: ..."
- over the suffixes (listed separated by commas)
"forsuffixes $=1, 2, 3: ... "
- infinite loop, "forever: ..."; to break out of the infinite loop
use "exitif" or "exitunless". You can use these break-statement in the
other loops too.
Examples
% define a path using a for-cycle
path q;
q = for i=0 upto 5: z[i] -- endfor z[6];
draw q withcolor red;
% invoke fun2() on all the args of fun()
def fun( text t ) = forsuffixes $=t: fun2($) endfor enddef;
% define a function that returns a path
vardef p(text t) =
k := 0;
forsuffixes $=t:
if ($ > k): z[$] -- else: z[$] fi
hide( k:=k+1 )
exitif( $ < k );
endfor
enddef;
draw p(8, 6, 4, 2, 0);
The syntax of the "if" statement is
if condition:
...
else:
...
fi
There is also "elseif:" that help to reduce the nesting of the "if"s.
7.A.11 Macroes
New functions (called "macro") can be defined.
These are important in writing
MetaPost code to extend
therion.
The syntax is
def function (expr ...) =
body_of_the_function
enddef;
The parameters of a macro are usually "expr" (expressions).
They can be also "suffix" (variables), or "text" (string of characters).
To invoke a macro passing the name of a variable to it, it is better
to declare the parameter as "suffix".
The return value of a macro is the result of the last statement before
"endgroup".
The "begingroup" and "endgroup" commands define a local scope.
Also "beginfig" and "endfig" define a local scope.
The "save" command, followed by the name of one or more variables,
tells MetaPost to store away the current value of those variables,
and replace them at the "endgroup".
The "interim" command assigns to a variable a temporary value, and replace it
with the old value at the "endgroup".
Another way to define a macro is the "vardef" command.
This is very much like a function: a "begingroup"/"endgroup" block
is automatically inserted. Moreover the name of the "vardef"
can have suffixes; for example, "vardef a[]b (expr p) = ...".
Two special variables are predefined: "@" is the last piece of the
name of the "vardef", "#@" is everything that come before it.
7.A.12 An example
You can easily find several metapost examples on the web.
The following is the drawing of the "danger" sign (an exclamation mark
inside a square rotatbe by 45 degrees).
beginfig(1);
s = 20.0; % scale
z0 = (200, 200); % offset
z1 = z0 + (0,-1)*s; % corners
z2 = z0 + (1,0)*s;
z3 = z0 + (0,1)*s;
z4 = z0 + (-1,0)*s;
z5 = 0.2 [ z1, z3 ];
z6 = 0.3 [ z1, z3 ];
z7 = 0.7 [ z1, z3 ];
z8 = 0.8 [ z1, z3 ];
z9 = z7 + (z8-z7) rotated 90;
z10 = z7 - (z8-z7) rotated 90;
pickup pencircle scaled (s/10);
draw z1 -- z2 -- z3 -- z4 -- cycle;
pickup pencircle scaled (s/8);
draw z5;
fill z6 -- z9 .. z8 .. z10 -- cycle;
endfig;
end
This code is pretty simple. Actually, you do not need all the
sofisticated commands of MetaPost to customize therion for your
cave drawings. The result of the above code is shwon in the
figure below.
Fig. 94. Danger sign
7.A.13 PostScript file
The command "shipout" generates the PostScript file. It takes as argument
a picture. The PostScript filename has extension ".N" where N is the number
specified in the command "beginfig".
The command "endfig" invokes "shipout currentpicture;".
At the end of a metapost file you must add the command "end;" which
tells to the interpreter mpost
to quit.
When your metapost file is ready, and execute
mpost file.mp
you get a list of files, "file.1", "file.2", ..., one for each figure.
These are almost PostScript files. If you want to visualize them
(with ghostview) or convert to pdf ( with ps2pdf) you may get some errors
since a few things are missing. In particular the fonts definition and that
of the command "fshow". Open the files of the figures with a text editor
and add the missing definitions at the beginning (in the prolog),
/cmr10 /CMR10 def
/fshow {exch findfont exch scalefont setfont show}bind def
This is not enough. The figure will be centered in the lower left corner
of the page, and you will see only part of it. To move it inside the page
add the PostScript command (use suitable x-y offset values).
You may also rotate it. For example,
590 22 translate
90 rotate
therion users - Thu Mar 4 17:04:18 2010
Prev Up Top Next Contents
This work is licensed under a Creative Commons
Attribution-NonCommercial-ShareAlike 2.5 License.