Therion is very powerful and flexible tool that allows to create and manage cave maps. It is also open to extensins to adapt it to particular needs. This is the advantage of the Open Source, and a modular design of the code.

This chapter describes how to extend therion

  • localizing therion (and xtherion) to your language;
  • inserting MetaPost and/or TeX code snippets;
  • font specifications;
  • creating new symbols.

Therion is distributed with support for english (en), cezch (cz), slovak (sk), and other languages from contributors: french (fr), spanish (sp), polish (po) and italian (it).

Adding a new language is very simple thanks to the fact that the localization is contained in the subdirectory thlang of therion, and there is a perl script, process.pl, to generate a localization file from the list of the strings for the different supported languages.

This scrip cna also be used to create an empty file for a given language, and include its content in the localization file, after it has been filled in with a text editor.

Since the script is in PERL, you must have a perl interpreter installed on your system. This is normal for every Linux and MacOS X distribution. If you do not have it (likely if you have Windows) you can download PERL from CPAN ((comprehensive PERL archive network), as well as the additional perl modules that you may need. The url is http://www.cpan.org.

The last hing you must do is to set the language in the configuration file of xtherion.

6.1.1 Localization

As an example we describe the localization for italian (it), so that you can have cave maps and atlases with italian legends, and the interface of xtherion in italian too.

Move into the directory therion/thlang and execute the command

      perl process.pl export it

. For other languages use the respective code, eg, “de” for german, and so on. This generates the text file texts_it.txt containing lines with the command name used by therion followed by lines with the string “it:” with nothing else on it.

You must open this file with a text editor and write the string (or phrase) in the locale language on the lines beginning with “it:”, ie, the language code. This is what therion will write when it generates the output. Every string or phrase must stay on a single line. Multiline labels or description are not supported. It is not possible to use the continuation combination (backslash-newline) either, because the perl script does not recognize it.

When you are doen with the editing, run the command

      perl process.pl update

This will include the content of the file texts_it.txt in the global file texts.txt, and removes the file texts_it.txt.

In case of errors it points them out to you. For instance if you forget to insert a string/phrase and leave a line with only the header “it:” it tells you, adding where in the file there is the missing translation. In this case, regenerate the file texts_it.txt, as you did before. It will have all the inputs you have entered, and you need only to fill in the missing translation. Then repeat the “update” command.

When everything is in order, run the script with no argument,

      perl process.pl

This generates the source files in the directory of therion:

     updating definitions from ../thsymbolset.cxx ... done
     updating definitions from ../thexpmap.cxx ... done
     updating definitions from ../thlocale.cxx ... done
     updating definitions from ../thmapstat.cxx ... done
     updating definitions from ../thpdf.cxx ... done

Move up in the directory of “therion”, recompile it, and reinstall it. Now therion is ready to generate cave maps with legends in italian.

6.1.2 Configuration

The last step is to specify the default language in the configuration file od therion. At a global level this is “/etc/therion.ini” (on Linux and MacOS X). At a local level there is “.therion/therion.ini” (on Linux) in your home directory. Open one of them with a text editor and search the string “language”. It is commented (there is a '#' in front of it). Make a copy of it, uncomment it and replace “en_UK” with “it” (the language code).

Alternatively you can specify the language with the layout option “language”. For example “language fr”.

Now try to generate surveys with the legends in different languages.

6.1.3 xtherion

Also xtherion can be localized, justlike therion. Go into the directory “xtherion/lang”, and repeat the procedure with the script “process.pl”: export the file “texts_XX.txt” (replace “XX” with your language code), edit it and write proper strings for the messages in your language. Update the file “texts.txt”. Finally execute the script without arguments.

You are not done. You must insert also the texts that will be displayed with the menu “Help | Controls”. move up in the “xtherion” directory and edit the file “msgusr.tcl”: you must insert an object for the text to display (again, replace “XX” with your language code):

   ::msgcat::mcset XX "xtherion_help_control" [encoding convertfrom utf-8 {
   -- write the text here --

Go up in the therion directory and execute “make install”.

xtherion has its initialization file, “/etc/xtherion.ini”. Open it with a text editor and search the string “mclocale”. It is usually commented (the line starts with '#') and with the language code “sk”. make a copy if it. Remove the comment from the copied line and replace “sk” with your language code.

6.1.4 Other extensions

Therion can handle other extension to the data presentation, ina modular way, as for the localization. Possible extensions are:

  • encodings
  • TeX encodings
  • macros of TeX and MetaPost

More details can be found in the Therion book [thbook 62].

The code command lets you affect the way therion processes your data. It can be used with one of the following arguments

  • “metapost”, to define code for MetaPost;
  • “tex-map”, to define code for TeX, generating maps;
  • “tex-atlas”, to define code for TeX, generating atlases.

The content of the command is passed to the specified processing command.

You may want to read the file “thmpost.cxx” from the therion sources.


6.2.1 Replacing a symbol

The following piece of code tells therion to insert the specified command in the input to MetaPost. In particular this command replaces the symbol “p_gradient” with the UIS symbol for the entrance: not very useful indeed):

   code metapost
     let p_gradient = p_entrance_UIS;


6.2.2 Lines thickness

You can change the thickness of the lines in the drawing by redefining the unit (which is called “u” in therion):

   code metapost

We saw that therion has five pre-defined pens: “PenA” (thick), “PenB”, “PenC”, “PenD”, and “PenE” (thin). You can redefine only one of the pens used by therion:

   code metapost
     def PenA =
       pencircle scaled (0.001);

You can redefine a symbol. You can start from the metapost code in therion (files with extension “.mp” in the directory “mpost”). For example [adapted from S. Mudrak 20060621],

     def l_floorstep (expr P) =
       pickup PenD;                        % thin pen
       len := arclength P;                 % arclength of the path
       ds := adjust_step(len, 0.25u);      % compute step between ticks
       for s=0 step ds until len:
         t := arctime s of P;              % path time coordinate
         mark_ ( P, t, 0.2u );             % draw a tick at "point t of P"
       pickup PenC;                        % normal pen
       thdraw P;                           % draw P

The function “mark_()” could be defined as follows:

   code metapost
     def mark_( expr P, t, s ) =
       pair q[];
       q1 := point t of P;                 % point P[t]
       q2 := direction t ot P rotated 90;  % tangent to P at P[t] rotated 90 deg
       thdraw q1 -- q2;

centerline (.th command)

6.2.3 Centerline color

The following code replaces the color of the centerline, and uses a continuous line instead of only the ticks at the stations [thexample 2]:

   code metapost
     def l_survey_cave (expr p) =
       draw p withpen PenD withcolor (1.0, 0.0, 0.0);

This section is taken from the wiki [thwiki 12]: it contains the procedure to replace the font sizes. It is expected that in the future one can redefine the fonts. Right now one can include some MetaPost code, that redefines the font_setup, in the layout. The standard code is roughly as follows:

   code metapost
   def fonts_setup (expr t,s,m,l,h) =
     write "\def\updown#1#2{\vbox{" &
         "\offinterlineskip" &
         "\setbox100=\hbox{#1}" &
         "\setbox101=\hbox{#2}" &
         "\ifnum\wd100>\wd101\hsize=\wd100\else\hsize=\wd101\fi" &
         "\centerline{\box100}\vskip4pt" &
         "\centerline{\box101}}}" &
         "\def\thlabel{\thnormalsize}" &
         "\def\thremark{\thsmallsize\si}" &
         "\def\thaltitude{\thsmallsize}" &
         "\def\thstationname{\thsmallsize}" &
         "\def\thdate{\thsmallsize}" &
         "\def\thheight{\thsmallsize}" &
         "\def\thheightpos{\thsmallsize+\ignorespaces}" &
         "\def\thheightneg{\thsmallsize-\ignorespaces}" &
         "\def\thframed{\thsmallsize}" &
     to "mptexpre.tex";
     write "\def\thtinysize{\size[" & decimal max(optical_zoom*t,0) & "]}" &
         "\def\thsmallsize{\size[" & decimal max(optical_zoom*s,0) & "]}" &
         "\def\thnormalsize{\size[" & decimal max(optical_zoom*m,0) & "]}" &
         "\def\thlargesize{\size[" & decimal max(optical_zoom*l,0) & "]}" &
         "\def\thhugesize{\size[" & decimal max(optical_zoom*h,0) & "]}"
     to "mptexpre.tex";
     write EOF to "mptexpre.tex";

To change one size you need to include a command specifing the size before the line “write EOF”. For example,

     write "\def\thstationname{\size[4]}" to "mptexpre.tex";

label (point)
As a matter of fact the “point” command of type “label” is followed by an argument that specifies the size of the text. Therefore to change the labels textsize you must consume the default scale and insert the new size, as in this example,

   code metapost
     def fonts_setup (expr t,s,m,l,h) =
       write "\def\thlabel#1{\size[32]}" to "mptexpre.tex";
       write "\def\threport#1{\size[16]}" to "mptexpre.tex";
       write EOF to "mptexpre.tex";

This code redefines also the point of type “report”, otherwise MetaPost raises an error when it is used.

Furthermore (rephrasing S. Mudrak):

In the future changing fonts sizes and styles should be simpler, and there > should be some examples in The Therion Book. At least the choice of the > color should be implemented sometime soon.

remark (point)
At the moment there is the “code metapost” option “fonts_setup” that allows to define the five basic font sizes, from the smallest ( tiny) to the largest ( huge). The points of type “label” use the third size ( medium); the points of type “remark” use the second size ( small). The definition of the “fonts_setup” command is in the file thmpost.cxx.

    code metapost
      \fonts_setup( 12, 16, 32, 64, 96 );

A symbol is a function to make a drawing. To define a symbol one needs to specify what this function does. To assign a symbol (for example when you write a map file in xtherion) amounts to write the name of this function in the data file, the one with extension “.th2”, so that when processed by therion the symbol function is invoked.

A new symbol can be inserted in a layout with the “code metapost” command, or it can be compiled in the therion program.

Every symbol has a name, composed by

  • a letter, 'p' (point), 'l' (line), 'a' (area), or 's' (special);
  • a type;
  • an optional subtype;
  • the id of the symbol (lowercase).

The newly defined symbol must be registered with the command “initsymbol( symbol_name )”, unless it is compiled in in therion.

pen (MetaPost)
The therion language has four predefined pens, differing by the thickness of the lines: “PenA” (thick), “PenB”, “PenC”, and “PenD” (thin). There are two commands to draw lines: “thdraw” and “thfill”. The first draws a line. The second fills also the area enclosed by the line. Do not use the MetaPost commands “draw” and “fill”.


6.4.1 Points

The point symbols have usually four parameters (exceptions: “section”, “label” and “station”):

  • P, position
  • R, rotation
  • S, scaling
  • A, alignment

These parameters define the transformation applyed to the symbol drawing when it is added to the map. The result of the symbol function (ie, the drawing of the symbol) is transformed by

     T = identity aligned A scaled S rotated R shifted P

Symbols are drawn in local coordinates, in which the drawing of the symbol is referred to the origin (0,0), and the units of length is u.

As an example we define a symbol made of a square, rotated 45 degrees, with an exclamation point inside. The figure below is the result.

   code metapost
     def p_entrance_MY (expr P,R,S,A)=
       T:=identity aligned A rotated R scaled S shifted P;
       thfill (0,-u)--(u,0)--(0,u)--(0,.9u)--(.9u,0)--(0,-.9u)--cycle;
       thfill (0,-u)--(-u,0)--(0,u)--(0,.9u)--(-.9u,0)--(0,-.9u)--cycle;
       thfill (.1u,-.45u)..(0,-.35u)..(-.1u,-.45u)..(0,-.55u)..cycle;
       thfill (0,-.2u)..(.1u,-.1u)--(.2u,.4u)..(0,.6u)..(-.2u,.4u)--(-.1u,-.1u)..cycle;
     let p_entrance = p_entrance_MY;



6.4.2 Lines

Line symbols have only one argument, the path of the line, expressed in absolute coordinates. Therefore the T trasformation is always the identity.

For example [thbook 59],

   def l_wall_bedrock_MY (expr P)=
     pickup PenB;
     thdraw P;


6.4.3 Areas

The area symbols, like the line symbols, have only one argument, the path of the area contour, expressed in absolute coordinates. The areas are region of the drawing and can be filled in three ways,

  • filling with symbols a (uniform or random) grid in the bounding box (bbox) of the path, and clipping the symbols drawings to the region inside the path;
  • colouring the region inside the path with a uniform color;
  • filling the region inside the path with a predefined pattern.

A pattern is specified using Metapost commands. For example [thbook 59],

     draw origin--10up withpen pensquare scaled (0.02u);
     patternxstep( .18u );
     patterntransform( identity rotated 45);
   def a_water_MY (expr P)=
     thclean P;
     thfill P withpattern pattern_water_MY;
6.4.4 Examples

If you want to draw a symbol using metapost you can start with an existing symbol and edit it. You need to remember a few points:

  • a line is a sequence of (x,y) pairs separated by “–” or by “..”. In the first case the line is straight, in the second it is smooth.
  • if the sequence ends with the word “cycle” the line is closed.
  • the command thdraw draws a line;
  • the command thfill fills the region inside the line with a color. Example 1

This is an example of point symbol.

   code metapost
      def p_gradient_MY (expr P,R,S,A) =
         U:=(.15u, .4u);    
         T:=identity aligned A rotated R scaled S shifted P;
         pickup PenC;
         #Left Hand side
         thdraw (-.3u, -.2u) -- (-.7u, .1u);
         thdraw (-.2u, -.1u) -- (-.4u, .6u);
         thdraw (0u, 0u) -- (0u, .9u);
         #Right side
         thdraw (.3u, -.2u) -- (.7u, .1u);
         thdraw (.2u, -.1u) -- (.4u, .6u);
      initsymbol ("p_gradient_MY");
   endcode Example 2

It is convenient to define the code for symbols (and other things) in a data file which will then be included in the configuration file, using the input command. Therefore the configuration file has something like

    input layout.th
    source main.th
    export map -layout plan -output ABC.pdf
    export map -layout print -output ABC_Printable.pdf

The “layout.th” file contains the layout commands and the definitions of the new symbols. The following code is by Ph. Schuchardt. Notice that

  • for the cave outline it uses “PenA”, the thick one;
  • the “gradient” symbol is redefined as in the previous example;
  • for the “sand” area the bounding box is filled with points randomly placed around the nodes of an irregular grid; they are then clipped to the area region, before drawing.
  • for the “debris” a “picture” object is defined composed by litle squares placed about the nodes of a grid that spans the bounding box (bbox) of the path “p”. The squares are also rotated by a random angle. The picture is then clipped to the region inside “p” and drawn.
  • the new symbols are initialized at the end;
  • and the default symbols are replaced with the new ones.
   layout plan
     scale 1 200 
     code tex-map
       \cavename={nome della grotta}
       \comment{testo del commento}
     code metapost
       def l_wall_bedrock_MY (expr P) =
         pickup PenA;
         thdraw P;
       def p_gradient_MY (expr P,R,S,A) =
           U:=(.15u, .4u);
           T:=identity aligned A rotated R scaled S shifted P;
           pickup PenC;
           # thdraw and thfill commands
       def a_sand_MY (expr p) =
         %  thclean p;
         pickup PenC;
         path q; q = bbox p;
         picture tmp_pic; 
         tmp_pic := image(
           for i = xpart llcorner q step .3u until xpart urcorner q:
             for j = ypart llcorner q step .3u until ypart urcorner q:
               draw origin shifted ((i,j) randomized 0.2u) withpen PenC;
         clip tmp_pic to p;
         draw tmp_pic;
       def a_debris_MY (expr p) =
         pickup PenC;
         path q, qq; q = bbox p;
         picture tmp_pic; 
         tmp_pic := image(
           for i = xpart llcorner q step u until xpart urcorner q:
             for j = ypart llcorner q step u until ypart urcorner q:
               qq := punked( ( (-.2u,-.2u)--(.2u,-.2u)--(.2u,.2u)--(-.2u,.2u)--cycle ) 
 	                randomized (u/2) )
                     rotated uniformdeviate(360) 
                     shifted ((i,j) randomized u);
 	      if xpart (p intersectiontimes qq) < 0:
 	        thclean qq;
 	        thdraw qq;
         clip tmp_pic to p;
         draw tmp_pic;
       initsymbol ("a_sand_MY");
       initsymbol ("a_debris_MY");
       initsymbol ("p_gradient_MY");
       initsymbol ("l_wall_bedrock_MY");
     symbol-assign area sand MY
     symbol-assign area debris MY
     symbol-assign line wall:bedrock MY
     symbol-assign point gradient MY
6.4.5 New symbols

Wookey wrote

It looks like we need to add the snippet provided to the symbols in mpost/thPoint.mp file and then rebuild therion.
Guys - how do we add new symbols like this? If the answer is 'rebuild therion from source' then something is wrong in the design… Maybe an extrernal path is checked as well as the internal library?
It must be possible to have an external symbols library. I know you built everything in to avoid people having problems with paths, but it is a horrible hack. At least for the debian version I would really like to move the metpost and tex stuff back into the places it should be, then I hope adding new symbols would be something that could be by users.

To get a deeper understanding of therion you can look at the source code, eventually. A way to browse the code is to open the files with an IDE (Integrated Development Environment), and use the tools it provides. You need to have a development environment for that.

This section describes how to generate HTML documenattion of the therion code, that you can see with any web browser. There are several programs that generate documentation from the source files, using the comments that the programmer wrote in them, and the structure of the coding language. Even if the source files lack the comments, the documentation is rich enough to allow a easier browsing and facilitate the reading of the code.

therion is written with comments for doxygen. This program can be downloaded from http://www.doxygen.org. You need first to create a doxygen configuration file. Go into the directory of therion and type

     doxygen -g doxy.cfg

This command creates the file “doxy.cfg”. You should edit it, inserting the name of the project (“Therion”), the version number, and the directory for the output of doxygen (you need to create it). Check the various options: in particular you might want doxygen to include the source code (.h and .c/.cxx) in the documentation, as well as all the other informations that can be useful.

Unfortunately terion code is not completely commented. Actually it is barely commented. Therefore, you can tell doxygen not to report “warnings”.

When you are done, type

     doxygen doxy.cfg

and, after a few seconds (or tens of seconds), you have the documentation in the output directory that you have specified. Open your web browser on the “index.html” page of that directory.

This appendix describes the most important MetaPost commands 13 .

MetaPost 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”.

6.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

pen (MetaPost)

6.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.

color (MetaPost)

6.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”.

transform (MetaPost)

6.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.

6.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.

path (MetaPost)

6.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) = t 3> Z1 + 3 t 2> (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(with pen pensquare scaled 0.4);  % set the pen

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.

6.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;

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)

6.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;”.

6.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” = (a 2 + b 2) 1/2, “a+-+b” = (a 2 - b 2) 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:

  • - nullari: for example, “true”, “false”, “whatever”;
  • - unari: 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”.
6.A.10 Control structures

MetaPost has the main control structures of a programming language: “for” loops, and “it” conditionals. These can be mixed in the definition of a path.

The syntax of the “for” loop is

    for i=0 step S until N:

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.


   % 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 );
   draw p(8, 6, 4, 2, 0);

The syntax of the “if” statement is

    if condition: 

There is also “elseif:” that help to reduce the nesting of the “if”s.

6.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 ...) =

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.

6.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).

     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;

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.

 Danger sign

6.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,

    /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)

     200 200 translate
  • tbe/wiki6.txt
  • Last modified: 8 years ago
  • by andrew.atkinson