## MetaPost

…is code to define what the labels and cave symbols in pdf and svg outputs look like.

(Add another metapost links here)

pstoedit translates PostScript and PDF graphics into other vector formats, Metapost format too.

TUG's listing of MetaPost on the Web

MetaPost tutorial, Robert Špalek, česky

Many interesting MetaPost examples, gallery what is possible to do with MP

Page with many links to Metapost documentation and examples

Learning METAPOST by Doing, André Heck (pdf)

Loria: The Metafun manual, Hans Hagen, 2017 (pdf)

or: Pragma: The Metafun manual, Hans Hagen, 2017 (pdf)

Puzzling graphics in METAPOST, Hans Hagen (pdf)

Many nice examples

Many links from Michio Matsuyama, but you have to copy the text and open it as html file

### Previewers

Online previewer Java based MetaPost Editor and Previewer (MEPer)

If you are brave Marco has written more than I ever wanted to know here Therion by Examples Metapost and here - Chapter 7

### How to create metapost for new symbols

Adapted from advice by Nikita Kozlov and Martin Sluka

- Create a new symbol with your favorite vector graphics editor,
- Save results to .eps format, and then
- Use pstoedit to convert the .eps to metapost,
- Adapt the code to work with Therion (Refer to section 7.4 of Marco Corvi's Therion by Examples), then
- Compile a test map and admire your work.

A limitation is that pstoedit converts only to polylines. It does not create 'curves' or other more sophisticated Metapost entities. It is enough to create user symbol for a tree for example.

Another way is to draw your symbol on graph paper and then create Metapost code for straight or smooth curved lines.

Both approaches will in due course require you to learn some Metapost!

You may check the very basic tutorial of Metapost here:http://meeting.contextgarden.net/2008/talks/2008-08-22-hartmut-metapost/mptut-context2008.pdf

#### Implementing redefined metapost examples (Bruce Mutton)

These examples show how redefined symbols like those below can be used, and includes a redefinition of Atlas so that it includes a north arrow on each page, and a redefinition of the continuation symbol so that it displays the associated text.

### How to get Therions MetaPost code (and Tex code)

You can use this code as a starting point to make your own customisations.

You can either start with the unadulterated source code (perhaps the best way, and as described here) or you can use the code that has been updated with any modifications already present in your current setup (often useful as well if you want to see the end result of your definitions and re-definitions)- as described below.

You need to run Therion in debug mode (command line -d option) to tell it to produce and retain a folder with interim outputs (not to be confused with layout-debug which can produce 2D outputs with station names, scrap names, intermediate scrap distortions etc).

The folder produced is called thTMPDIR

It contains;

- data.mp = a dump of all the metapost code used by Therion
- data.tex = a dump of all the tex code used by Therion

and perhaps less usefully…

- th_texts.tex = ascii dump of all tex variables
- th_legend.tex = similar dump of the legend
- and much more…

Skim through data.mp and data.tex to find definitions and snippets of code that you'd like to edit.

Copy these to a code-tex or code-metapost block in a layout in one of your *.th or thconfig-*.* files, and make your edits.

The files produced in thTMPDIR will now reflect the code you have entered in your layouts.

By the way, you might be able to use the following to track down errors in metapost code (or in scrap drawings).

faq#how_to_find_where_a_metapost_error_is_occurring

### Symbol Sizing and Positioning

On Sun, Feb 7, 2010 Bruce wrote:

Is u (and v w for that matter) intended to correspond to a

particular drawn entity size in the finished pdf, or are they just

arbitrary variables for which one can calculate the value of, using

the code in the initialise definition?

Bruce

**u** allows nonlinear scaling of symbols depending on scale. The macro initialize assigns a fixed value to 'u' which will be used in pdf for that scale. On average, diameter of point symbols is (or is intended to be) 1u in the output.

**v** and **w** behave differently (v could be used e.g. for some area fills with decreasing distance among symbols for smaller scales but only up to a certain threshold, then bigger distance again; w is almost constant). Currently they are not (or perhaps only occasionally) used in symbols design.

In the beginning we wanted to do some sort of optimization of values assigned to u, v, w but did not manage to do it so far. It would be useful if somebody could test alternative values (and alternative breaks for map scale in the initialize macro) for various scales and various styles of map drawing (lot of symbols vs. sparsely filled map). Good setup of these values could improve map appearance substantially.

Cheers, Martin

Refer to the section **New Map Symbols**, **Point Symbols** in The Therion Book.

If you want your custom point symbol to be able to be aligned, rotated or scaled by users according to options set in th2 drawing files, then your `T:= identity…`

line will need include those keywords and the variables parsed in the symbol `def`

statement. A number of the point symbol examples below do not, possibly intentionally preventing those symbols from being aligned, rotated or scaled respectively.

- Symbol coordinates (0u, 0u) are the origin point for that symbol. This is the place in the symbol drawing that corresponds exactly to the point symbol location that you will draw in a scrap with XTherion.

- Your symbols should generally be defined so that they fit within the size range -0.5u to +0.5u in both x and y axes, although you can use larger or smaller values in either dimension. This is because we generally want the map symbols to be about ‘u’ in size.

This image is a symbol that has been defined with maximum x and y coordinates, supposedly, of 0.7u, both positive and negative. The insertion point is at the intersection of the cross hairs, and the pdf has been exported with a rotate value of 15 degrees. It has been overlaid with some code that highlights the origin and alignment loci, and unit symbol size, u, as described below.

The symbol alignment option relies on the definition of a U: variable, otherwise your symbol will cause an error and stop Therion if a user sets an alignment option other than `centre`

. The U: variable is depicted by the light blue box.

- U: is a scaling factor for alignment parameters, such as right, top or top-right.

U: defines the size of the x horizontal (left-right) and y vertical (up-down) offset when a symbol is aligned, so the x and y components of U: should be set to be around the maximum absolute value of x and y symbol coordinates, respectively. ie for a symmetrically placed symbol who’s perimeter will just touch the insertion point, set U:=(0.5x symbol width, 0.5x symbol height).

- If a U: component is smaller than a maximum corresponding symbol coordinate, an aligned symbol will overlap the insertion point.
- If a U: component is larger than a maximum corresponding symbol coordinate, an aligned symbol will have a gap from the insertion point.
- If your symbol has its greatest dimension on a diagonal, then you should increase the U: components accordingly, to avoid unintentional drawing overlaps for aligned symbols.

As one 'use case' for aligning symbols is to enable them to be placed ‘near’ to another symbol, and be always positioned appropriately at a variety of output scales, I am going to suggest that U: components for user friendly point symbols should always be just a little greater than half the symbol dimension. ie the light blue box should enclose the symbol. That way, an aligned symbol can always leave a pleasing small gap from its insertion point.

When writing a new point symbol and testing that it aligns and rotates nicely, it can be a bit tricky to figure out where the origin, insertion point, and alignment loci are located. So I have written some code that you can temporarily place inside a symbol, to get a visual representation of how well placed its origin and alignment loci are with respect to its insertion point, and of its size compared to the nominal default size of u.

Here it is inserted into an electric light symbol definition. The code is between the lines with % % %. It creates a green insertion point, a red origin point that represents the (0u, 0u) origin of the symbol, a light blue rectangle that represents the loci of the alignment options (left, top-left etc), and a grey unit symbol size. Note that this code requires that T:= … rotated BEFORE aligned. If your symbol uses T:= … aligned BEFORE rotated, then the code needs to be modified slightly.

After writing the code, I realised that this symbol was in fact larger than 0.7u in the y direction, therefore the U: variable is not tall enough, the symbol is not centered around around its (0u,0u) coordinates (which might be OK if you want the space below the luminaire to be part of the 'symbol') and it is just a bit (but probably acceptably) larger than u in size!

def p_u_electriclight (expr pos,theta,sc,al) = U:=(0.7u, 0.7u); % Reduce size of the symbol. The default size is too big. interim defaultscale:=0.4sc; T:=identity rotated theta aligned al scaled defaultscale shifted pos; %corrected to rotate THEN align % % % SYMBOL PARAMETER INDICATOR (origin, insertion, alignment box, u box) % Placing this code directly after T:= identity line will put the indicators under the symbol % Placing this code immediately before enddef will put the indicators over top of the symbol % Before use you need to correctly assign the parsed variable aliases in the next two rows from the def statement above rotation:= theta; %set this to the third parsed variable (ie theta) pair alignment; alignment:= al; %set this to the last parsed variable (ie al) % show symbol origin, (0,0) red thdraw fullcircle scaled 0.15u withpen PenD withcolor red; % show symbol insertion point, (0,0) green thdraw fullcircle shifted -(xpart alignment * xpart U, ypart alignment * ypart U) rotated -rotation withpen PenD withcolor green; % show U alignment box light blue q:= (xpart U, -ypart U) -- (xpart U, ypart U) -- (-xpart U, ypart U) -- (-xpart U, -ypart U) -- cycle; thdraw q shifted -(xpart alignment * xpart U, ypart alignment * ypart U) rotated -rotation withpen PenD withcolor 0.5blue+0.5white; % show u box grey thdraw unitsquare scaled u shifted (-0.5u, -0.5u) withpen PenD withcolor 0.1black+0.5white; % % % pickup PenC; thdraw fullcircle scaled 0.5u shifted (0.0u, 0.7u); thdraw (-0.5u, -0.6u) -- (-0.5u, 0.0u); thdraw (-0.5u, 0.0u) .. (-0.35u, 0.55u) .. (0.0u, 0.7u); thdraw (0.0u, 0.7u) .. (0.35u, 0.55u) .. (0.5u, 0.0u); thdraw (0.5u,0.0u) -- (0.5u, -0.6u); thdraw (-0.7u, -0.6u) -- (0.7u, -0.6u); enddef;

Here is an example with the above point symbol that has been redefined with three different U: settings, and inserted with `-align top-right`

. On the left, U:=(1.0u, 1.0u) [U/u=1.4], in the centre, U:=(0.7u, 0.7u) [U/u=1.0], on the right, U:=(0.5u, 0.5u) [U/u= 0.7]. Note that the alignment, top-right, is relative to the local coordinate system in the scrap, not necessarily to the output page coordinate system. In these examples it does match the output page orientation, because the scrap has 'north up'.

The smudgy line is intended to represent an object that the alignment is intended to avoid, ie a wall. You can see that U: = symbol dimension is OK, but U:= smaller than symbol dimension is probably what most users would want to avoid.

I'm going to suggest that the best values for U: components are between [U/u=1.0] to [U/u=1.2]

An here are some examples with a slightly improved U: variable, with the symbol aligned top-left and oriented 30 degrees, and the output rotated 15, 105, 195, 285 degrees.

And one last example, using `point water`

, with the above code added, that demonstrates how align is related to scrap coordinates rather than the output coordinates.

Bruce

## Setting pen thicknesses

This can be used to set a minimum pen thickness, so that all other pens take their sizes relative to that pen thickness. This can be useful for publications that mandate a specific pen width, which can be harder to control with scaling. (This can be done by setting the “u” value, but that causes all symbols to be scaled too.)

code metapost def minimumpen = 0.18pt enddef; def PenA = pencircle scaled (minimumpen*1/0.35) enddef; def PenB = pencircle scaled (minimumpen*0.7/0.35) enddef; def PenC = pencircle scaled (minimumpen*0.5/0.35) enddef; def PenD = pencircle scaled (minimumpen) enddef; def PenX = pencircle scaled (minimumpen*1.2/0.35) enddef; endcode

## General Symbol Examples

For example; centrelines, water, point altitudes

### Point Symbols

#### Define a user point symbol for a stalagmite boss

def p_u_boss (expr pos,theta,sc,al)= T:=identity aligned al rotated theta scaled sc shifted pos; pickup PenD; p := (0.08u,0.25u)..(0,0.29u)..(-0.08u,0.25u); q := (0.16u,0.5u)..(0u,0.58u)..(-0.16u,0.5u); for i=0 upto 9: thdraw p rotated 36i; thdraw q rotated 36i; endfor p := fullcircle scaled 0.15u; thdraw p; enddef;

#### Define an entrance symbol as a theta inside a diamond

def p_entrance_MY (expr pos,theta,sc,al)= U:=(.2u,.5u); T:=identity aligned al rotated theta scaled sc shifted pos; path p; p = (-.3u,-.25u) -- (-.2u,-.25u){dir 135} .. (0u, .25u) .. {dir 225}(.2u,-.25u) -- (.3u,-.25u); thdraw p withpen PenA; thdraw unitsquare scaled u shifted (-0.5u,-0.5u) rotated 45 withpen PenD; enddef;

#### Define a user point symbol for a single large irregular block

def p_u_block(expr pos,theta,sc,al) = T:=identity aligned al rotated theta scaled sc shifted pos; path p q; p := (2.3u,0.9u)--(0.65u,1u)--(-0.9u,0.6u)--(-2.15u,-0.1u)--(-2.35u,-0.25u)--(-2.5u,-0.5u)--(-2u,-0.65u)--(-0.75u,-0.65u)--(0.6u,-0.7u)--(1.1u,-0.5u)--(2.1u,-0.15u)--cycle; pickup PenB; thdraw p; % The following line uses the code from Colour Dependant Visualization of Symbols by Bruce Mutton if known colour_block_bg: thfill p withcolor colour_block_bg; else: thfill p withcolor (0.75,0.75,0.75); fi; q := (-2.5u,-0.5u)--(-2u,-0.65u)--(-0.75u,-0.65u)--(0.6u,-0.7u)--(1.1u,-0.5u)--(2.1u,-0.15u)--(2.3u,0.9u)--(2.5u,0.7u)--(2.5u,0.5u)--(2.25u,-0.9u)--(1.1u,-1.3u)--(0.5u,-1.5u)--(-0.75u,-1.4u)--(-2u,-1.15u)--(-2.35u,-0.65u)--cycle; thdraw q; thfill q withcolor(0.6,0.6,0.6); pickup PenD; path p; p := (-2u,-0.65u)--(-1.9u,-1u); thdraw p; path p; p := (0.6u,-0.7u)--(0.5u,-1.3u); thdraw p; path p; p := (2.1u,-0.15u)--(2.3u,-0.4u); thdraw p; enddef; initsymbol("p_u_block");

#### Point - Artificial Electric Light

Bill Gee

# This code defines an artificial electric light. Used in tourist sections of a cave. # by Bill Gee May 2019 def p_u_electriclight (expr pos,theta,sc,al) = U:=(0.3u, 0.3u); % Reduce size of the symbol. The default size is too big. interim defaultscale:=0.4sc; T:=identity aligned al rotated theta scaled defaultscale shifted pos; pickup PenC; thdraw fullcircle scaled 0.5u shifted (0.0u, 0.7u); thdraw (-0.5u, -0.6u) -- (-0.5u, 0.0u); thdraw (-0.5u, 0.0u) .. (-0.35u, 0.55u) .. (0.0u, 0.7u); thdraw (0.0u, 0.7u) .. (0.35u, 0.55u) .. (0.5u, 0.0u); thdraw (0.5u,0.0u) -- (0.5u, -0.6u); thdraw (-0.7u, -0.6u) -- (0.7u, -0.6u); enddef;

—-

#### Shell limestone

Point symbol for shell limestone:

def p_u_shell (expr pos,theta,sc,al)= T:=identity shifted pos; pickup PenB; numeric turns, radius; path ss, cesta; pair za, zb; turns = 1.55; radius = .3u; za = ( xpart(origin)+0, ypart(origin)+.1u ) rotated 370 turns; zb = ( xpart(origin)+.3u, ypart(origin)+0 ) rotated 360 turns; cesta := za--zb; ss := (origin for t=1 upto 360 turns: -- dir t scaled t endfor) scaled (radius/turns/360); thdraw ss withcolor (0.3); thdraw (cesta cutbefore ss) withcolor (0.3); enddef;

#### P-hangers that face the right way

The default “anchor” symbol takes up a lot of space. It also resists rotation. This produces a P-hanger icon instead. It respects rotation, so that if the “orientation” arrow points to the right, the P-hanger will point in the chosen direction. In addition, it selects the correct direction to face, so that the loop of the hanger always points down the page. It intentionally has a thinner line pointing into the rock, so that it appears to pierce the wall of the cave (just like a real P-hanger).

code metapost % a P-hanger def p_anchor_MY (expr P,R,S,A)= U:=(.25u,.4u); T:=identity aligned A rotated R scaled S shifted P; % thick part sticking out of the rock thdraw (0,0)--(0,.4u) withpen PenB withcolor black; % thin part in the rock thdraw (0,-.2u)--(0,0) withpen PenC withcolor black; % the loop should hang down the "page", based on the rotation if (R > 0) and (R < 180): Facing:=-1 else: Facing:=1 fi; % stubs to hold the semicircle thdraw (0,.1u)--(Facing*.1u,.1u) withpen PenB withcolor black; thdraw (0,.4u)--(Facing*.1u,.4u) withpen PenB withcolor black; % semicircle thdraw halfcircle scaled .3u rotated (Facing*-90) shifted (Facing*.1u,.25u) withpen PenB withcolor black; enddef; initsymbol("p_anchor_MY"); endcode

Use it with this line in your layout:

symbol-assign point anchor MY

#### Warning triangle

Warning triangle with exclamation mark, and yellow background:

code metapost % a warning triangle def p_u_warning (expr P,R,S,A)= scale:=0.5u; sin120:=sind(120); cos120:=cosd(120); U:=(sin120*scale,scale); T:=identity aligned A rotated R scaled S shifted P; % yellow triangle thfill (0,scale)--(sin120*scale,cos120*scale)--(sind(240)*scale,cosd(240)*scale)--cycle withcolor (1,1,0); % black triangle outline thdraw (0,scale)--(sin120*scale,cos120*scale) withpen PenB withcolor black; thdraw (sin120*scale,cos120*scale)--(sind(240)*scale,cosd(240)*scale) withpen PenB withcolor black; thdraw (sind(240)*scale,cosd(240)*scale)--(0,scale) withpen PenB withcolor black; % line of ! thdraw (0,0)--(0,.5*scale) withpen PenB withcolor black; thdraw (0,-.25*scale)--(0,-.25*scale) withpen PenB withcolor black; % dot of ! enddef; initsymbol("p_u_warning"); endcode

Select this as point type “u” with “-subtype warning” in its options. Use it with this line in your layout:

text en "point u:warning" "warning/danger"

#### Magnetic effects

Certain rocks can cause a compass to give the wrong reading. This icon can be used to show areas where this happens (ie. where the survey may be unreliable as a result); a spinning compass:

code metapost % a spinning compass def p_u_magnetism (expr P,R,S,A)= scale:=0.5u; halfline:=(0.5u/20S); %half thickness of PenC - pen thicknesses do not scale with S pointheight:=scale*.9; pointwidth:=scale*.4; U:=(scale,scale); T:=identity aligned A rotated (R-20) scaled S shifted P; % a circle thdraw fullcircle scaled 2scale withpen PenC withcolor black; % filled triangle thfill (0,pointheight)--(pointwidth,0)--(-pointwidth,0)--cycle withcolor black; % black triangle outline thdraw (0,-pointheight+halfline)--(pointwidth-halfline,0) withpen PenC withcolor black; thdraw (0,-pointheight+halfline)--(-pointwidth+halfline,0) withpen PenC withcolor black; % spin arcs, a full circle is path 0-8, anticlockwise, starting from the right thdraw subpath (2.4,3.5) of fullcircle scaled 1.5scale withpen PenC withcolor black; thdraw subpath (6.4,7.5) of fullcircle scaled 1.5scale withpen PenC withcolor black; enddef; initsymbol("p_u_magnetism"); endcode

Select this as point type “u” with “-subtype magnetism” in its options. Use it with this line in your layout:

text en "point u:magnetism" "magnetism"

### Line Symbols

#### View whole centerline for underground

Stacho Mudrak

If you wish to view whole centerline for underground, just redefine symbol in layout:

code mpost let l_survey_cave = l_survey_surface_SKBB; endcode

—-

#### Green colored continuous centerline

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

def l_survey_cave (expr p) = pickup PenC; draw p withcolor 0.5green; enddef;

#### Make unsurveyed wall lines light-weight and dashed

A sample of how it looks is in the 'line rope' example below.

code metapost %Bruce Mutton 2010.06.20 for Therion 5.3.9 def l_wall_unsurveyed (expr P) = T:=identity; pickup PenC; thdraw P dashed evenly scaled (2*optical_zoom); enddef; endcode

—-

#### Visualize cave centreline shot flags with colour for splay and duplicate, and dash for approximate shot flags

For version 5.3.12+ Dec2013 (Bruce Mutton)

code metapost #thin grey cave splays, yellow duplicates and dashed approximate legs def l_survey_cave (expr P) = % always draws full centreline, rather than short stubs like default cave centrelines T:=identity; pickup PenC; if ATTR__shotflag_splay: drawoptions(withcolor(0.5,0.5,0.5) withpen PenD); thdraw P; % grey & thin drawoptions(); else: % not splay but may have either or both duplicate and approx flags set if ATTR__shotflag_duplicate: drawoptions(withcolor (1,1,0)); % differentiate duplicate with colour yellow fi; if ATTR__shotflag_approx: thdraw P dashed evenly scaled optical_zoom; % differentiate approx with dashed else: thdraw P; fi; thdrawoptions(); fi; enddef; endcode

I was trying to get the duplicate and approximate symbols to appear in the legend as below, but so far it does not work…

initsymbol("l_survey_cave_duplicate"); %not working def l_survey_cave_duplicate_legend = l_survey_cave_duplicate(((.2,.2) -- (.8,.8)); inscale) %not working enddef;

—-

#### Define NZSS line wall presumed

Draws dashes with v shaped tick marks outside the passage like we tend to do in New Zealand…

A sample of how it looks is in the 'line rope' example below.

code metapost %Bruce Mutton 2010.06.20 uses general code and adjust_step defined in therion source code by Martin Budaj %for Therion 5.3.8 def l_wall_presumed (expr P) = T:=identity; cas := 0; % cursor to step along path dlzka := arclength P; mojkrok:=adjust_step(dlzka, 1.5u); % symbol length nudged to be multiple of path length q := (-0.2u,-0.4u)--(0,0)--(0.2u,-0.4u); % define v shape forever: t1 := arctime (cas + mojkrok*1/5) of P; t := arctime (cas + mojkrok/2) of P; t2 := arctime (cas + mojkrok*4/5) of P; pickup PenA; % thick thdraw (subpath (t1,t2) of P); % dash pickup PenC; % thin thdraw q rotated angle(thdir(P,t)) shifted (point t of P ); % v shape cas := cas + mojkrok; exitif cas > dlzka - (2*mojkrok/3); % for rounding errors endfor; enddef; endcode

#### Define NZSS line chimney (aven)

code metapost %Bruce Mutton 2012.06.10 uses general code for l_pit_UIS defined in therion source code by Martin Budaj 5.3.9 % dots on righthand (rock) side of line spaced 0.2u, 0.2u same as floor-step ticks def l_chimney (expr P) = T:=identity; cas := 0; % cursor to step along path dlzka := arclength P; mojkrok:=adjust_step(dlzka, 0.25u); % symbol length nudged to be multiple of path length q:= (0.20u,-0.20u) -- (0.21u,-0.21u); % dot pickup PenC; %2nd thinnest pen forever: t := arctime cas of P; thdraw q rotated angle(thdir(P,t)) shifted (point t of P ); % draw dots cas := cas + mojkrok; exitif cas > dlzka + (mojkrok / 3); % for rounding errors endfor; pickup PenB; %2nd thickest pen thdraw P; %continuous line enddef; endcode

#### Define NZSS line ceiling-step

This is just Therions default SKBB ceiling step, reflected so that it matches the UIS convention with the tick marks pointing away from the void space.

code metapost %Bruce Mutton 2012.06.16 uses general code for l_ceilingstep_SKBB defined in therion source code by Martin Budaj 5.3.9 % but ticks on righthand (rock) side of line def l_ceilingstep (expr P) = T:=identity; cas := 0; % cursor to step along path dlzka := arclength P; mojkrok:=adjust_step(dlzka, 0.8u); % symbol length nudged to be multiple of path length pickup PenC; forever: t1 := arctime (cas + mojkrok*1/5) of P; t := arctime (cas + mojkrok/2) of P; t2 := arctime (cas + mojkrok*4/5) of P; thdraw (subpath (t1,t2) of P); mark_ (P,t,-0.2u); % change sign to -0.2u cas := cas + mojkrok; exitif cas > dlzka - (2*mojkrok/3); % for rounding errors endfor; enddef; endcode

#### Define NZSS line ceiling-meander

This is just Therions default SKBB ceiling meander, with the symbols reflected so that it matches the UIS convention with the tick marks pointing away from the void space.

code metapost %Bruce Mutton 2012.06.16 uses general code for l_ceilingmeander_SKBB defined in therion source code by Martin Budaj 5.3.9 % but ticks on outside (rock) side of lines def l_ceilingmeander (expr P) = pair Pp; pair Pd; pair Pv; T:=identity; cas := 0; % cursor to step along path dlzka := arclength P; mojkrok:=adjust_step(dlzka, 0.8u); % symbol length nudged to be multiple of path length pickup PenC; forever: t := arctime (cas + mojkrok/2) of P; Pp := (point t of P); Pd := unitvector(thdir(P,t)); Pv := Pd rotated 90; thdraw (Pp + 0.2u * Pv) -- (Pp + 0.3u * Pv); % add 0.1u to each moves ticks outside thdraw (Pp + 0.2u * Pv + 0.2u * Pd) -- (Pp + 0.2u * Pv - 0.2u * Pd); thdraw (Pp - 0.2u * Pv) -- (Pp - 0.3u * Pv); % subtract 0.1u to each moves ticks outside thdraw (Pp - 0.2u * Pv + 0.2u * Pd) -- (Pp - 0.2u * Pv - 0.2u * Pd); cas := cas + mojkrok; exitif cas > dlzka - (2*mojkrok/3); % for rounding errors endfor; enddef; endcode

#### Draw a plank walk and (rope) handrail

def l_u_plankwalk (expr P) = T:=identity; cas := 0; dlzka := arclength P; mojrok := adjust_step(dlzka, 0.5u); pickup PenD; forever: t := arctime cas of P; thdraw ((point t of P) + 0.5 * u * unitvector(thdir(P,t) rotated 90)) -- ((point t of P) - 0.5 * u * unitvector(thdir(P,t) rotated 90) ); cas := cas + mojrok; exitif cas > dlzka + (mojrok/3); % for rounding errors endfor; pickup PenC; %thdraw P; %draw path withcolor (0.5, 0 ,0) enddef;

def l_u_handrail (expr P) = T:=identity; pair zz[]; for t = 0 upto length P - 1: zz1 := point t of P; zz2 := point t+1 of P; zz3 := 0.5[zz1,zz2]; zz4 := 0.25[zz1,zz2]; zz5 := 0.75[zz1,zz2]; pickup PenA; thdraw zz1 -- zz2 withcolor(.67,.41,.28); %planks thdraw zz1 shifted (0,1.6u) .. zz4 shifted (0,1.2u) .. zz3 shifted (0,1.6u) .. zz5 shifted (0,1.3u) .. zz2 shifted (0,1.6u) withcolor(.67,.41,.28); pickup pencircle scaled 1pt; thdraw zz1 shifted (0,-1.2u) -- zz1 shifted (0,2u) withcolor(.67,.41,.28); %first post thdraw zz3 -- zz3 shifted (0,2u) withcolor(.67,.41,.28); %mid post endfor; thdraw zz2 shifted (0,-6u) -- zz2 shifted (0,2u) withcolor(.67,.41,.30); %last post enddef;

#### Define a doline

def l_u_doline (expr P) = T:=identity; laenge:= arclength P; symsize:=adjust_step(laenge,2u); triangle_width:=symsize/10; cur:=(symsize-triangle_width)/2; pickup PenC; forever: t1 := arctime (cur) of P; t := arctime (cur + triangle_width/2) of P; t2 := arctime (cur + triangle_width) of P; thfill (subpath (t1,t2) of P) -- ((point t of P) + symsize/2 * unitvector(thdir(P,t) rotated 90)) -- cycle; thdraw (point t2 of P) --((point t of P) + symsize/2 * unitvector(thdir(P,t) rotated 90)) -- (point t1 of P) withcolor (0.5, 0, 0); cur := cur + symsize; exitif cur > laenge - (1*symsize/3); % for rounding errors t1:=arctime (cur) of P; endfor; enddef;

#### Define Line Handrail

Andrew Atkinson

def l_u_rail (expr P) = T:=identity; cas := 0; dlzka := arclength P; mojkrok:=adjust_step(dlzka, 0.8u); pickup PenC; forever: t0 := arctime (cas) of P; t1 := arctime (cas + mojkrok*2/5) of P; t := arctime (cas + mojkrok/2) of P; t4 := arctime (cas + mojkrok*3/5) of P; t5 := arctime (cas + mojkrok) of P; thdraw (subpath (t0,t1) of P); thdraw (subpath (t4,t5) of P); drawdot (point t of P); #mark_ (P,t,0.02u); #mark_ (P,t,-0.02u); #f := (P,t,0.2u); #draw f; cas := cas + mojkrok; exitif cas > dlzka - (2*mojkrok/3); % for rounding errors endfor; enddef; initsymbol("l_u_rail")

#### Strata

Line symbol for strata for cross sections. It works exactly as line section symbol but you should use -clip off option:

def l_u_strata (expr P) = T:=identity; path Q; Q = punked P; for t = 0 upto length P - 1: pair zz[]; zz1 := point t of P; zz2 := point t+1 of P; zz3 := postcontrol t of P; zz4 := precontrol t+1 of P; linecap:=0; if (length(zz3-1/3[zz1,zz2]) > 0.1pt) or (length(zz4-2/3[zz1,zz2]) > 0.1pt): zz5 = whatever[zz1,zz2]; (zz3-zz5) = whatever * (zz1-zz2) rotated 90; pickup pencircle scaled 1 mm; draw zz1--zz5 dashed evenly; pickup PenA; draw zz1--zz5 withcolor background; zz6 = whatever[zz1,zz2]; (zz4-zz6) = whatever * (zz1-zz2) rotated 90; pickup pencircle scaled 1 mm; draw zz2--zz6 dashed evenly; pickup PenA; draw zz2--zz6 withcolor background; else: pickup pencircle scaled 1 mm; draw zz1--zz2 dashed evenly; pickup PenA; draw zz1--zz2 withcolor background; fi; endfor; enddef;

#### Fault

Line symbol for fault. It works exactly as line section symbol but you should use -clip off option:

def l_u_fault (expr P) = T:=identity; path Q; Q = punked P; pickup PenA; for t = 0 upto length P - 1: pair zz[]; zz1 := point t of P; zz2 := point t+1 of P; zz3 := postcontrol t of P; zz4 := precontrol t+1 of P; if (length(zz3-1/3[zz1,zz2]) > 0.1pt) or (length(zz4-2/3[zz1,zz2]) > 0.1pt): zz5 = whatever[zz1,zz2]; (zz3-zz5) = whatever * (zz1-zz2) rotated 90; draw zz1--zz5 dashed evenly; zz6 = whatever[zz1,zz2]; (zz4-zz6) = whatever * (zz1-zz2) rotated 90; draw zz2--zz6 dashed evenly; else: draw zz1--zz2 dashed evenly; fi; endfor; enddef;

### Area Symbols

#### Show area water in a different color

Martin Budaj

Add in layout:

code metapost def a_water (expr p) = T:=identity; thfill p withcolor (0.1, 0.2, 0.8); enddef; endcode

Colors are in order R, G, B — 0=0 1=255. Color (0.1, 0.2, 0.8) means (25 51 204) in Photoshop - quite dark blue. Light blue could be for example (123 213 255) in Photoshop - it is (123/255, 213/255, 255/255) or (0.48, 0.84 1.0) for Metapost.

See also this spreadsheet to visualise and convert between colour formats.

#### Modification MetaPost code for NSS (Philip Schuchardt)

This is how you overload metapost symbols:

######### thconfig file ###########

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

########## Heres my layout.th ################

layout plan scale 1 200 #Working map scale #scale 1 400 #scale 1 600 #1" to 50' #base-scale 1 600 units imperial legend on color map-fg altitude transparency on debug station-names #PDF DOCUMENTION doc-author "Philip Schuchardt" code tex-map \cavename={Alva Blankenship Cave (WORKING COPY } \comment{Cartography By: Philip Schuchardt and Philip Balister \copyright 2006 VPI Cave Club} endcode code metapost def l_wall_bedrock_AMER (expr P) = T:=identity; pickup PenA; thdraw P; enddef; def p_gradient_AMER (expr pos,theta,sc,al) = U:=(.15u, .4u); T:=identity aligned al rotated theta scaled sc shifted pos; pickup PenC; #Left Hand side thdraw (-.3u, -.2u) -- (-.7u, .1u); thdraw (-.2u, -.1u) -- (-.4u, .6u); #Centerline thdraw (0u, 0u) -- (0u, .9u); #Right side thdraw (.3u, -.2u) -- (.7u, .1u); thdraw (.2u, -.1u) -- (.4u, .6u); enddef; def a_sand_AMER (expr p) = T:=identity; % 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; endfor; endfor; ); clip tmp_pic to p; draw tmp_pic; enddef; def a_debris_AMER (expr p) = T:=identity; 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; fi; endfor; endfor; ); clip tmp_pic to p; draw tmp_pic; enddef; initsymbol ("a_sand_AMER"); initsymbol ("a_debris_AMER"); initsymbol ("p_gradient_AMER"); initsymbol ("l_wall_bedrock_AMER"); endcode symbol-assign area sand AMER symbol-assign area debris AMER symbol-assign line wall:bedrock AMER symbol-assign point gradient AMER endlayout

#### Modification of fill densities

Stacho Mudrák

code metapost % pattern for water, .18u is density of lines. beginpattern(pattern_water_MY); draw origin--10up withpen pensquare scaled (0.02u); patternxstep(.18u); patterntransform(identity rotated 45); endpattern; % pattern for sump, 0.25u is density in this case. beginpattern(pattern_sump_MY); draw origin--(0,.25u) withpen pensquare scaled (0.02u); draw origin--(.25u,0) withpen pensquare scaled (0.02u); patterntransform(identity rotated 45); endpattern; def a_water (expr Path) = T:=identity; thclean Path; thfill Path withpattern pattern_water_MY; enddef; def a_sump (expr Path) = T:=identity; thclean Path; thfill Path withpattern pattern_sump_MY; enddef; endcode

… and modify 0.18u in water pattern (and/or 0.25u in sump pattern) to number you need.

In therion, area symbols are defined two ways:

- Using patterns - no randomness, very small PDF file size. You need to redefine pattern (begin|endpattern) and symbol macro (a_water).
- Using drawing/clipping into Path - random look, large PDF size. Here you need to redefine only symbol (a_water) macro.

Water is the case of pattern fills. Blocks and others are random.

For other area symbols, see mpost/thArea.mp file for metapost source codes.

#### POINT BLOCK +size adjust (symbolsize)

Stefan Oswald

code metapost def p_blocks_UIS (expr pos,theta,sc,al)= symbolsize:=1.0u; %Factor*u; Factor=size of the blocks U:=(.5u,.5u); T:=identity aligned al rotated theta scaled sc shifted pos; pickup PenC; thdraw (.0symbolsize,.0symbolsize)--(1.0symbolsize,-.5symbolsize)--(0.0symbolsize,-1.5symbolsize)--(-1.0symbolsize,-1.0symbolsize)--cycle; thdraw (.5symbolsize,-.25symbolsize)--(1.0symbolsize,.5symbolsize)--(0.0symbolsize,1.5symbolsize)--(-0.5symbolsize,.5symbolsize); thdraw (.0symbolsize,.0symbolsize)--(.0symbolsize,.5symbolsize)--(-1.5symbolsize,.5symbolsize)--(-1.5symbolsize,-0.5symbolsize)--(-0.5symbolsize,-0.5symbolsize); enddef; endcode

#### AREA BLOCK + density adjust (distance)

Stefan Oswald

code metapost def a_blocks (expr p) = distance:=1; T:=identity; pickup PenC; path q, qq; q = bbox p; picture tmp_pic; uu := max(u, (xpart urcorner q - xpart llcorner q)/100, (ypart urcorner q - ypart llcorner q)/100); tmp_pic := image( for i = xpart llcorner q step distance*uu until xpart urcorner q: for j = ypart llcorner q step distance*uu until ypart urcorner q: qq := punked (((-.5uu,-.5uu)--(.5uu,-.5uu)--(.5uu,.5uu)--(-.5uu,.5uu)--cycle) randomized (uu/2)) rotated uniformdeviate(360) shifted ((i,j) randomized 1.0uu); if xpart (p intersectiontimes qq) < 0: thclean qq; thdraw qq; fi; endfor; endfor; ); clip tmp_pic to p; draw tmp_pic; enddef; endcode

#### Make area AUT sand more spaced out and more random

A sample of how it looks is in the 'area point colour water' example below.

code metapost %Bruce Mutton 2010.06.20, after original author Georg Pacher %for Therion 5.3.8 beginpattern(pattern_sand); pickup PenC; p:= origin -- (0.01u,0.01u); for i=0.0u step 0.4u until 2.4u: %AUT is step 0.2u for j=0.0u step 0.4u until 2.4u: %AUT is step 0.2u draw p rotated uniformdeviate(360) shifted ((i,j) randomized 0.4u); %%AUT is 0.09u endfor; endfor; if BaseScale<=2.5: my_step:=2.6u; %mystep controls tessilation pattern, must synchronise with i, j above, was 2.4u else: my_step:=2.8u; %was 2.6u fi; patternstep(my_step,my_step); endpattern;

def a_sand (expr Path) = T:=identity; %thclean Path; %makes passage colour more intense under area, not good for sand thfill Path withpattern pattern_sand ; enddef; endcode

#### Area blocks with colored rock-borders only (not filled)

Martin Budaj

symbol-colour area blocks [67 31 4]

code metapost def a_blocks (expr p) = T:=identity; pickup PenC; path q, qq; q = bbox p; picture tmp_pic; uu := max(u, (xpart urcorner q - xpart llcorner q)/100, (ypart urcorner q - ypart llcorner q)/100); tmp_pic := image( for i = xpart llcorner q step 2uu until xpart urcorner q: for j = ypart llcorner q step 2uu until ypart urcorner q: qq := punked (((-.5uu,-.5uu)--(.5uu,-.5uu)--(.5uu,.5uu)--(-.5uu,.5uu)--cycle) randomized (uu/2)) rotated uniformdeviate(360) shifted ((i,j) randomized 1.6uu); if xpart (p intersectiontimes qq) < 0: thdraw qq; fi; endfor; endfor; ); clip tmp_pic to p; draw tmp_pic; enddef;

This is modified a_blocks_SKBB definition with “thclean qq;” statement removed. Stacho Mudrák

##### Another solution

Another solution is to leave “thclean qq” on its original position and change

clip tmp_pic to p; draw tmp_pic;

to

clip tmp_pic to p; drawoptions(); draw tmp_pic;

at the end of the macro definition. This approach preserves filling the blocks with a background colour.

#### Customisable Area Blocks with Different Number of Sides

Andrew Atkinson

Blocks shown as produced by default settings, at about half scale.

The grid is made of horizontal and vertical grids, but due to the way the starting regular polygon is derived the starting point is always top middle, this makes no randomness makes the squares come out at 45°

Various things could be improved.

The settings can no be overridden by using

-attr

on each area, therefore having different types and density of blocks in different areas.

overlap <`true|false`

>

Do the blocks overlap the border, if false an attempt is made to shink the block until it is inside or out

Default false

separation <`number`

>

Proportion to the size of separation of centres of the blocks as set out in a rectangular grid

Default 0.7

block_random <`number`

>

Max each point of the base block can be moved. Too big and they can intersect themselves

Default 0.7\

base_rotation <`number`

>\
Rotation from 0 of base block, can be used to set all blocks to the same angle, not relavant if random rotation is set to 360

Default 0

random_rotation <`number`

>

Rotation either side of base rotation eg 20 will be plus or minus 10 each side

Default 360

min_scale <`number`

>

Minimum multiplier used for the base shape

Default 0.7

max_scale <`number`

>

Added to the minimum multiplier to get the maximum scale

Default 0.6

aspect <`number`

>

How much longer the block is than it is wide, before randomising

Default 1.5

shift_random <`number`

>

Max random amount block can be moved from the original grid

Deafult 0.75

shapes <`number,number,number,number`

>

Set the ratio of different sided block, triangle, square, pentagon, hexagon. Must be single digits

Default 1,3,4,2

**Code for blocks**

initsymbol ("a_blocks_BCA"); def a_blocks_BCA (expr p) = T:=identity; %Derived from one of the built in blocks symbols %No error checking on the attr so can break badly % Andrew Atkinson 2019 %Do the blocks overlap the border, if false an attempt is made to shink the block until it is inside or out boolean overlap; overlap:= if known ATTR_overlap: scantokens(ATTR_overlap) else: false fi; % Proportion to the size of separation of centres of the blocks as set out in a rectangular grid %FIXME: Really need to check if it is number and not zero in for some cases separation:= if known ATTR_separation: scantokens(ATTR_separation) else: 0.7 fi; % Max each point of the base block can be moved. Too big and they can intersect themselves block_random:= if known ATTR_block_random: scantokens(ATTR_block_random); else: 0.7 fi; % Rotation from 0 of base block, can be used to set all blocks to the same angle base_rotation:= if known ATTR_base_rotation: scantokens(ATTR_base_rotation) else: 0 fi; % Rotation either side of base rotation eg 20 will be plus or minus 10 each side random_rotation:= if known ATTR_random_rotation: scantokens(ATTR_random_rotation) else: 360 fi; % Minimum multiplier used for the base shape min_scale_factor:= if known ATTR_min_size: scantokens(ATTR_min_size) else: 0.7 fi; % Added to the minimum multiplier to get the maximum scale add_scale_factor:= if known ATTR_max_size: scantokens(ATTR_max_size) else: 0.6 fi; % How much longer the block is than it is wide, before randomising aspect:= if known ATTR_aspect: scantokens(ATTR_aspect) else: 1.5 fi; % Max random amount block can be moved from the original grid shift_random:= if known ATTR_shift_random: scantokens(ATTR_shift_random) else: 0.75 fi; % Set the propotions of different sided block if known ATTR_shapes: b_tri:=scantokens substring (0,1) of ATTR_shapes; b_quad:=scantokens substring (2,3) of ATTR_shapes; b_pent:=scantokens substring (4,5) of ATTR_shapes; b_hex:=scantokens substring (6,7) of ATTR_shapes; else: b_tri:=1; b_quad:=3; b_pent:=4; b_hex:=2; fi; pickup PenC; path q, qq; q = bbox p; pair outside; outside:= ulcorner q + up; picture tmp_pic; uu := max(u, (xpart urcorner q - xpart llcorner q)/100, (ypart urcorner q - ypart llcorner q)/100); iu := uu * aspect; blocks := b_tri+b_quad + b_pent + b_hex; tmp_pic := image( for i = xpart llcorner q step separation * aspect * uu until xpart urcorner q: for j = ypart llcorner q step separation*uu until ypart urcorner q: pick_sides := uniformdeviate(blocks); % This is probably a better way to impliment the different sided blocks calculates the vertices of polygons %for (i = 0; i < n; i++) { % printf("%f %f\n",x + r * Math.cos(2 * Math.PI * i / n), y + r * Math.sin(2 * Math.PI * i / n)); %} if pick_sides < b_tri: qq := punked (((.5iu,0)--(-0.25iu,.43uu)--(-.25iu,-0.43uu)--cycle) randomized (block_random * uu)) scaled (uniformdeviate(add_scale_factor)+min_scale_factor) rotated (base_rotation + random_rotation / 2 - uniformdeviate(random_rotation) ) shifted ((i,j) randomized (shift_random * uu)); elseif pick_sides < b_tri + b_quad: qq := punked (((0.5iu,0)--(0,0.5uu)--(-0.5iu,0)--(0,-0.5uu)--cycle) randomized (block_random * uu)) scaled (uniformdeviate(add_scale_factor)+min_scale_factor) rotated (base_rotation + random_rotation / 2 - uniformdeviate(random_rotation) ) shifted ((i,j) randomized (shift_random * uu)); elseif pick_sides < b_tri + b_quad + b_pent: qq := punked (((0.5iu,0)--(.15iu,0.48uu)--(-0.4iu,0.29uu)--(-0.4iu,-0.29uu)--(0.15iu,-0.48uu)--cycle) randomized (block_random * uu)) scaled (uniformdeviate(add_scale_factor)+min_scale_factor) rotated (base_rotation + random_rotation / 2 - uniformdeviate(random_rotation) ) shifted ((i,j) randomized (shift_random * uu)); else: qq := punked (((0.5iu,0)--(0.25iu,0.43uu)--(-0.25iu,0.43uu)--(-0.5iu,0)--(-0.25iu,-0.43uu)--(0.25iu,-0.43uu)--cycle) randomized (block_random * uu)) scaled (uniformdeviate(add_scale_factor)+min_scale_factor) rotated (base_rotation + random_rotation / 2 - uniformdeviate(random_rotation) ) shifted ((i,j) randomized (shift_random * uu)); fi; if not overlap: forever: % Repeatedly reduces the size of the image, as this is done round zero it also moves it to the zero location, until it fits in the area exitif xpart (p intersectiontimes qq) < 0; qq:= qq scaled (0.99 ); endfor; fi if pointinside((i,j),p,outside): thclean qq; thdraw qq; fi; endfor; endfor; ); % clip tmp_pic to p; %this appears not to be needed as the pointinside removes any outside the area drawoptions(); % no idea what this does! draw tmp_pic; enddef;

The base_rotation is an attempt to produce bedding plane breakdown, it could do with more time but this is possible

using the settings

area blocks -attr shapes 1,2,4,7 -attr seperation 0.5 -attr block_random 0.7 -attr base_rotation 20 -attr random_rotation 5 -attr min_scale 0.5 -attr aspect 7

#### Transparent area

Q: Is there an additionally possibility to make this definition so that the area will be a bit transparent?

A: Try this code:

def_transparent_rgb(tr_lgrey, 0.73, 0.71, 0.75);

def a_u_lgrey(expr P) = T:=identity; thfill P withtransparentcolor tr_lgrey; enddef;

There are a few predefined transparent colors, the most interesting of them is tr_bg (current scrap background). Standard opacity value (defined in the layout section) is applied. M. Budaj

### Label and Text Examples

#### To make the debug station names smaller

Stacho Mudrak

Currently, there is no easy way to do this, but it is possible. You just need to redefine fonts_setup metapost macro using layout. Just add following code to your layout:

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}" & "\def\thwallaltitude{\thtinysize}" 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 "\def\thstationname{\size[4]}" to "mptexpre.tex"; write EOF to "mptexpre.tex";

enddef; initialize(Scale); endcode

It may look crazy at first sight, but it is not so bad. I have just added this line to the standard code:

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

… and this line tells metapost to use font size 4 for station names.

#### Altitude Point

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

This label requires to specify the position of text relative to point with help of -altitude. In this case -altitude bottom-right

def p_altitude(expr pos)= T:=identity shifted pos; pickup PenD; p:=(-.3u,0)--(.3u,0); thdraw p; thdraw p rotated 90; p:=fullcircle scaled .2u; thclean p; thdraw p; enddef; vardef p_label@#(expr txt,pos,rot,mode) = if mode=1: thdrawoptions(withcolor .8red + .4blue); p_altitude(pos); % append "m" to label picture txtm; txtm:=image( draw txt; interim labeloffset:=0; label.urt(btex \thaltitude m etex, lrcorner txt); ); % give extra offset in case of l/r/t/b alignment pair ctmp; ctmp:=center thelabel@#("x", (0,0)); if (xpart ctmp * ypart ctmp)=0: interim labeloffset:=(.4u); else: % diagonal alignment interim labeloffset:=(.2u); fi; % draw label lab:=thelabel@#(txtm, pos); draw lab _thop_; % use color thdrawoptions(); bboxmargin:=0.8bp; write_circ_bbox((bbox lab) smoothed 2); else: if mode=7: interim labeloffset:=(u/8) fi; lab:=thelabel@#(txt, pos); if mode>1: pickup PenD fi; if mode=2: process_uplabel; elseif mode=3: process_downlabel; elseif mode=4: process_updownlabel; elseif mode=5: process_circledlabel; elseif mode=6: process_boxedlabel; elseif mode=7: process_label(pos,rot); % station name elseif mode=8: process_filledlabel(pos, rot); else: process_label(pos,rot); fi; fi; enddef;

#### Make 'point height' have P prefix for pits and C prefix for climbs

Martin Budaj

You just need to add following to your layout:

code mpost verbatimtex \def\thheightpos{C}\def\thheightneg{P} etex

and use “point 0 0 height -value [+10 m]” or “point 0 0 height -value [-85 m]” in your data to get C10 or P85.

#### Conditional Printing of Text Labels

Forum post describing some labelling issues and how to conditionally print labels

(Thomas' 'Scale Dependant Visualization' posts below show a tidier way of redefining the built in metapost, that will better inherit future changes to the default label metapost)

## Special Symbol Examples

Examples of North arrows, scale-bars, gridlines etc

### North Arrows

#### I want my north arrow to have a label, like "Norte Geografico"

Carlos Grohmann & Martin Budaj

def s_northarrow_SKBB (expr rot) = T:=identity scaled 0.7 rotated -rot; begingroup interim defaultscale:=1; label(btex Norte Geografico etex, (0,-1cm)); endgroup; thdraw (-.5cm,-1cm)--(0,1.5cm)--(.5cm,-1cm)--(0,-.5cm)--cycle; thfill (-.5cm,-1cm)--(0,1.5cm)--(0,-.5cm)--cycle; enddef;

#### Northarrow 1

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

def s_northarrow (expr rot) = begingroup interim defaultscale:=0.5; % scale your north arrow here T:=identity scaled defaultscale rotated -rot; pickup pencircle scaled (0.08cm * defaultscale); thdraw (-.4cm,-1.4cm)--(0,2.8cm)--(.4cm,-1.4cm)--cycle; p:=fullcircle scaled 1.6cm; thclean p; thdraw p; p:=(0.95cm,0)--(0.65cm,0); thdraw p; thdraw p xscaled -1; pickup pencircle scaled (0.12cm * defaultscale); p:=(0.28cm,0.42cm); thdraw p--(p yscaled -1)--(p xscaled -1)--(p scaled -1); endgroup; enddef;

#### Northarrow 2

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

def s_northarrow (expr rot) = begingroup interim defaultscale:=0.7; % scale your north arrow here T:=identity scaled defaultscale rotated -rot; interim linecap:=squared; interim linejoin:=rounded; thfill (-.5cm,-.1cm)--(0,2.5cm)--(.5cm,-.1cm)--cycle; pickup pencircle scaled (0.08cm * defaultscale); thdraw (0,0)--(0,-2.5cm); pickup pencircle scaled (0.16cm * defaultscale); p:=(0.4cm,0.6cm); thdraw ((p--(p yscaled -1)--(p xscaled -1)--(p scaled -1)) shifted (0,-1.0cm)); label.rt(thTEX("mg") scaled 1.6, (.6cm,-1.6cm)) transformed T; endgroup; enddef;

#### Northarrow 3

from Stacho Mudrák for version 5.3.x…

* distributed under the GNU General Public License.*

def s_northarrow_3 (expr rot) = T:=identity; picture tmp_pic; tmp_pic = image ( begingroup interim defaultscale:=3; label.top("N", origin shifted (0,2.2cm)); endgroup; thdraw (-.4cm,.4cm)--(0,2cm)--(.4cm,.4cm)--(2cm,0cm)--(.4cm,-.4cm)--(0,-2cm)--(-.4cm,-.4cm)--(-2cm,0)--cycle; thfill (-.4cm,.4cm)--(0,2cm)--(0,0)--cycle; thfill (.4cm,-.4cm)--(0,-2cm)--(0,0)--cycle; thfill (.4cm,.4cm)--(2cm,0)--(0,0)--cycle; thfill (-.4cm,-.4cm)--(-2cm,0)--(0,0)--cycle; ); draw tmp_pic scaled 0.5 rotatedaround(origin, -rot); enddef;

#### Northarrow 4

:metapost:s_northarrow-Nmag.png?150|]]

from Dirk Peinelt for 5.3.16…

I combine this compass rose with a creation date in the map-header (/currentdate), as a date variable is not present in metapost.

Martin Sluka: There is simple way to add actual date into Metapost code. I add modified variation after original code.

If the CS is not set, the declination is Zero, and so based on the declination, the northarrow is a Nmag arrow:

North grid/true rotate the whole plan with the north arrow. (meridianal Convergence)

def s_northarrow (expr rot) = valscal=1.2; % scale your north arrow here decl:=MagDecl; T:=identity; picture tmp_pic; tmp_pic = image ( pickup pencircle scaled .3; thfill fullcircle scaled 4cm withcolor 1white; thdraw fullcircle scaled 3.1cm; thdraw fullcircle scaled 4.05cm; pickup pencircle scaled .1; thdraw fullcircle scaled 3cm; thdraw fullcircle scaled 4cm; pickup pencircle scaled .2; thdraw (dir(45)*2.025cm)--(dir(45)*3.7cm); thdraw (dir(135)*2.025cm)--(dir(135)*3.7cm); thdraw (dir(225)*2.025cm)--(dir(225)*3.7cm); thdraw (dir(315)*2.025cm)--(dir(315)*3.7cm); pickup pencircle scaled .1; for whereto=0 step 15 until 345: thdraw dir(whereto)*.65cm--dir(whereto)*.9cm; thdraw dir(whereto)*1.4cm--dir(whereto)*1.5cm; endfor; for whereto=0 step 5 until 355: thdraw dir(whereto)*.65cm--dir(whereto)*.8cm; thdraw dir(whereto)*1.45cm--dir(whereto)*1.5cm; endfor; for whereto=0 step 1 until 359: thdraw dir(whereto)*1.94cm--dir(whereto)*2cm; endfor; pickup pencircle scaled 1; thdraw fullcircle scaled 1cm; thdraw fullcircle scaled 1.1cm; thdraw fullcircle scaled 1.3cm withpen pencircle scaled .3; vald=90-decl; texrot=0-decl; drawarrow(dir(vald)*-2cm--dir(vald)*2cm) withpen pencircle scaled .2; if (MagDecl <> 0): thdraw image(label.top(btex $mg$ etex, (0,0)) scaled .5 rotated texrot;) shifted (dir(vald)*2.04cm); fi; thfill (1.06cm,1.06cm)--(0,.2cm)--(-1.06cm,1.06cm)--(-.2cm,0)--(-1.06cm,-1.06cm)--(0,-.2cm)--(1.06cm,-1.06cm)--(.2cm,0)--cycle; thfill (-.2cm,.2cm)--(0,2cm)--(0,0)--cycle; thfill (.2cm,-.2cm)--(0,-2cm)--(0,0)--cycle; thfill (.2cm,.2cm)--(2cm,0)--(0,0)--cycle; thfill (-.2cm,-.2cm)--(-2cm,0)--(0,0)--cycle; thfill (.2cm,.2cm)--(-0,2cm)--(0,0)--cycle withcolor 1white; thfill (.2cm,-.2cm)--(2cm,0)--(0,0)--cycle withcolor 1white; thfill (-.2cm,-.2cm)--(0,-2cm)--(0,0)--cycle withcolor 1white; thfill (-.2cm,.2cm)--(-2cm,0)--(0,0)--cycle withcolor 1white; pickup pencircle scaled .2; thdraw (-.2cm,.2cm)--(0,2cm)--(.2cm,.2cm)--(2cm,0cm)--(.2cm,-.2cm)--(0,-2cm)--(-.2cm,-.2cm)--(-2cm,0)--cycle; thfill fullcircle scaled .56cm withcolor 1white; pickup pencircle scaled .1; thdraw (.28cm,0)..(0,.28cm)..(-.28cm,0)..(0,-.28cm)..cycle; pickup pencircle scaled .4; thdraw (.2cm,0)..(0,.2cm)..(-.2cm,0)..(0,-.2cm)..cycle; if (MagDecl = 0): label.bot(btex $Nmag$ etex, (0,2.6cm)); else: label.bot(btex $N$ etex, (0,2.6cm)); fi; label.lft(btex $E$ etex, (2.6cm,0)); label.rt(btex $W$ etex, (-2.6cm,0)); label.top(btex $S$ etex, (0,-2.6cm)); ); thdraw tmp_pic scaled valscal rotatedaround(origin, -rot); enddef;

#### Northarrow 4a

With actual date

If you want to use another font, check, please, one which include character “space”.

def s_northarrow (expr rot) = valscal=1.2; % scale your north arrow here decl:=MagDecl; T:=identity; picture tmp_pic; tmp_pic = image ( pickup pencircle scaled .3; thfill fullcircle scaled 4cm withcolor 1white; thdraw fullcircle scaled 3.1cm; thdraw fullcircle scaled 4.05cm; pickup pencircle scaled .1; thdraw fullcircle scaled 3cm; thdraw fullcircle scaled 4cm; pickup pencircle scaled .2; thdraw (dir(45)*2.025cm)--(dir(45)*3.7cm); thdraw (dir(135)*2.025cm)--(dir(135)*3.7cm); thdraw (dir(225)*2.025cm)--(dir(225)*3.7cm); thdraw (dir(315)*2.025cm)--(dir(315)*3.7cm); pickup pencircle scaled .1; for whereto=0 step 15 until 345: thdraw dir(whereto)*.65cm--dir(whereto)*.9cm; thdraw dir(whereto)*1.4cm--dir(whereto)*1.5cm; endfor; for whereto=0 step 5 until 355: thdraw dir(whereto)*.65cm--dir(whereto)*.8cm; thdraw dir(whereto)*1.45cm--dir(whereto)*1.5cm; endfor; for whereto=0 step 1 until 359: thdraw dir(whereto)*1.94cm--dir(whereto)*2cm; endfor; pickup pencircle scaled 1; thdraw fullcircle scaled 1cm; thdraw fullcircle scaled 1.1cm; thdraw fullcircle scaled 1.3cm withpen pencircle scaled .3; vald=90-decl; texrot=0-decl; drawarrow(dir(vald)*-2cm--dir(vald)*2cm) withpen pencircle scaled .2; if (MagDecl <> 0): string z; z = ("mg " & (decimal day) & ". " & (decimal month) & ". " & (decimal year)); thdraw image(label.urt( z infont "ptmr8r", (0,0)) scaled .5 rotated texrot;) shifted (dir(vald)*2.04cm); fi; thfill (1.06cm,1.06cm)--(0,.2cm)--(-1.06cm,1.06cm)--(-.2cm,0)--(-1.06cm,-1.06cm)--(0,-.2cm)--(1.06cm,-1.06cm)--(.2cm,0)--cycle; thfill (-.2cm,.2cm)--(0,2cm)--(0,0)--cycle; thfill (.2cm,-.2cm)--(0,-2cm)--(0,0)--cycle; thfill (.2cm,.2cm)--(2cm,0)--(0,0)--cycle; thfill (-.2cm,-.2cm)--(-2cm,0)--(0,0)--cycle; thfill (.2cm,.2cm)--(-0,2cm)--(0,0)--cycle withcolor 1white; thfill (.2cm,-.2cm)--(2cm,0)--(0,0)--cycle withcolor 1white; thfill (-.2cm,-.2cm)--(0,-2cm)--(0,0)--cycle withcolor 1white; thfill (-.2cm,.2cm)--(-2cm,0)--(0,0)--cycle withcolor 1white; pickup pencircle scaled .2; thdraw (-.2cm,.2cm)--(0,2cm)--(.2cm,.2cm)--(2cm,0cm)--(.2cm,-.2cm)--(0,-2cm)--(-.2cm,-.2cm)--(-2cm,0)--cycle; thfill fullcircle scaled .56cm withcolor 1white; pickup pencircle scaled .1; thdraw (.28cm,0)..(0,.28cm)..(-.28cm,0)..(0,-.28cm)..cycle; pickup pencircle scaled .4; thdraw (.2cm,0)..(0,.2cm)..(-.2cm,0)..(0,-.2cm)..cycle; if (MagDecl = 0): label.bot(btex $Nmag$ etex, (0,2.6cm)); else: label.bot(btex $N$ etex, (0,2.6cm)); fi; label.lft(btex $E$ etex, (2.6cm,0)); label.rt(btex $W$ etex, (-2.6cm,0)); label.top(btex $S$ etex, (0,-2.6cm)); ); thdraw tmp_pic scaled valscal rotatedaround(origin, -rot); enddef;

### Scalebars

#### Scalebar 1

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

def s_scalebar (expr l, units, txt) = begingroup interim warningcheck:=0; tmpl:=l / Scale * cm * units / 2; tmpx:=l / Scale * cm * units / 5; tmph:=5bp; % bar height endgroup; pickup PenC; draw (-tmpl,0)--(tmpl,0)--(tmpl,-tmph)--(-tmpl,-tmph)--cycle; p:=(0,0)--(tmpx,0)--(tmpx,-tmph)--(0,-tmph)--cycle; for i:=-2.5 step 2 until 2: fill p shifted (i * tmpx,0); endfor; begingroup interim labeloffset:=3.5bp; for i:=0 step (l/5) until (l-1): tmpx:=tmpl * (i * 2 / l - 1); label.top(thTEX(decimal (i)),(tmpx,0)); endfor; label.top(thTEX(decimal (l) & "\thinspace" & txt),(tmpl,0)); label.bot(thTEX("Originalmassstab = 1 : " & decimal round(Scale*100)),(0,-tmph)); endgroup; enddef;

#### Scalebar 2

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

def s_scalebar (expr l, units, txt) = begingroup interim warningcheck:=0; tmpl:=l / Scale * cm * units / 2; tmpx:=l / Scale * cm * units / 5; tmph:=5bp; % bar height endgroup; pickup PenC; draw (-tmpl,0)--(tmpl,0)--(tmpl,-tmph)--(-tmpl,-tmph)--cycle; p:=(0,0)--(tmpx,0)--(tmpx,-tmph)--(0,-tmph)--cycle; for i:=-2.5 step 2 until 2: fill p shifted (i * tmpx,0); endfor; begingroup interim labeloffset:=3.5bp; for i:=0 step (l/5) until (l-1): tmpx:=tmpl * (i * 2 / l - 1); label.bot(thTEX(decimal (i)),(tmpx,-tmph)); endfor; label.bot(thTEX(decimal (l) & "\thinspace" & txt),(tmpl,-tmph)); label.top(thTEX("Massstab 1 : " & decimal round(Scale*100)),(0,0)); endgroup; enddef;

#### Scalebar Bar length adjustment

from Andrew Atkinson

Some of us have fussy editors, who point out that due to the drawing of the rectangle for the scale bar the black lines are not exactly the same size as the white ones.

To fix this for the two scale bars above

Replace

draw (-tmpl,0)--(tmpl,0)--(tmpl,-tmph)--(-tmpl,-tmph)--cycle;

with

#Adjusted to make lines not stick out: 0.25*u/10,0 is half thickness of PenC draw (-tmpl+0.25*u/10,0)--(tmpl-0.25*u/10,0); draw (tmpl-0.25*u/10,-tmph)--(-tmpl+0.25*u/10,-tmph);

#### Scalebar 3

layout LayoutScalebar3 # Scalebar by Chris Hayes code metapost def s_scalebar (expr l, units, txt) = begingroup interim warningcheck:=0; tmp05:=5 * (l / Scale * cm * units / 100); tmp10:=10 * (l / Scale * cm * units / 100); tmp20:=20 * (l / Scale * cm * units / 100); tmp40:=40 * (l / Scale * cm * units / 100); tmp60:=60 * (l / Scale * cm * units / 100); tmp80:=80 * (l / Scale * cm * units / 100); tmp100:=100 * (l / Scale * cm * units / 100); scal05:=5 * l / 100; scal10:=10 * l / 100; scal20:=20 * l / 100; scal40:=40 * l / 100; scal60:=60 * l / 100; scal80:=80 * l / 100; brht:= 5bp; lblht:= 8bp; endgroup; pickup PenC; draw (0,0)--(0,brht)--(tmp100,brht)--(tmp100,0)--(0,0); draw (tmp05,0)--(tmp05,brht); draw (tmp10,0)--(tmp10,brht); draw (tmp20,0)--(tmp20,brht); draw (tmp40,0)--(tmp40,brht); draw (tmp60,0)--(tmp60,brht); draw (tmp80,0)--(tmp80,brht); fill (tmp05,0)--(tmp10,0)--(tmp10,brht)--(tmp05,brht)--cycle; fill (tmp20,0)--(tmp40,0)--(tmp40,brht)--(tmp20,brht)--cycle; fill (tmp60,0)--(tmp80,0)--(tmp80,brht)--(tmp60,brht)--cycle; begingroup label.top(thTEX(decimal (l) & "\thinspace" & txt),origin+(tmp100,lblht)); label.top(thTEX(decimal (scal80)),origin+(tmp80,lblht)); label.top(thTEX(decimal (scal60)),origin+(tmp60,lblht)); label.top(thTEX(decimal (scal40)),origin+(tmp40,lblht)); label.top(thTEX(decimal (scal20)),origin+(tmp20,lblht)); label.top(thTEX(decimal (scal10)),origin+(tmp10,lblht)); label.top(thTEX(decimal (scal05)),origin+(tmp05,lblht)); label.top(thTEX(decimal (0)),origin+(0,lblht)); endgroup enddef; endcode endlayout LayoutScalebar3

### Gridlines

#### Change grid symbols from cross hairs to continuous lines

from Stacho Mudrak (mostly) and Bruce Mutton 2007

code metapost def s_hgrid (expr xpos, ypos, xsize, ysize) = pickup PenD; draw ( if xpos < 0: 0 else: -xsize/2 fi, 0 ) -- ( if xpos > 0: 0 else: xsize/2 fi, 0 ) withcolor 0.1black+0.5white; draw ( 0, if ypos < 0: 0 else: -ysize/2 fi ) -- ( 0, if ypos > 0: 0 else: ysize/2 fi ) withcolor 0.1black+0.5white; enddef; endcode

## Scale Dependant Visualization of Symbols

Examples of scale dependent labeling and symbol display etc

A lot of this does not require metapost code (ie much of it can be done with default therion layout syntax), so maybe put this topic on a page of it's own?

from Thomas Holder for version 5.2.x…

* distributed under the GNU General Public License.*

def l_rockborder (expr p) = if abs(llcorner p - urcorner p) > u: l_rockborder_UIS(p); fi; enddef; def l_rockedge (expr p) = if abs(llcorner p - urcorner p) > u: l_rockedge_UIS(p); fi; enddef;

## Colour Dependant Visualization of Symbols

Examples of symbols that plot differently, dependant on whether particular colour
variables are defined.
Provides an easy way to toggle between producing maps optimised for black and white, and maps optimised for colour production.

**Code to redefine area and point water symbols**

Bruce Mutton 2010-2011 for Therion 5.3.8, 5.3.9

The area water symbols have much more spaced hatch lines, more consistent with what we traditionally use in New Zealand. The black and white point and area water has no background shading whereas the colour versions do.

#Patterns similar to standard definition of pattern_water_UIS and pattern_sump_UIS #Gives b&w shaded symbols with borders, unless custom colours are defined #in which case colour backgrounds defined in LayoutColourSymbols are used code metapost beginpattern(pattern_water); draw origin--10up withpen pensquare scaled (0.04u); % line thickness patternxstep(.50u); % spacing patterntransform(identity rotated 45); endpattern; beginpattern(pattern_sump); draw origin--(0,.50u) withpen pensquare scaled (0.04u); draw origin--(.50u,0) withpen pensquare scaled (0.04u); patterntransform(identity rotated 45); endpattern; def p_water (expr pos,theta,sc,al)= %Bruce Mutton 2010.06.20 for Therion 5.3.8 U:=(.425u,.3u); T:=identity aligned al rotated theta scaled sc shifted pos; pickup PenD; p:=fullcircle xscaled (1.2u) yscaled (0.8u) randomized (0.1u) rotated uniformdeviate (-45); if known colour_water_bg: thfill p withcolor colour_water_bg; else: thfill p withcolor white; fi; thfill p withpattern pattern_water; %%% withcolor black; %but with failed attempt at black hatch thdraw p; %outline enddef; def a_water (expr Path) = %Bruce Mutton 2010.06.20 for Therion 5.3.8 T:=identity; thclean Path; pickup PenD; if known colour_water_bg: thfill Path withcolor colour_water_bg; else: thfill Path withcolor white; fi; thfill Path withpattern pattern_water; %%thdraw Path; %outline, not needed as area drawn is defined by line border anyway %and border can be made invisible with subtype invisible where water meets sump in elevation enddef; def a_sump (expr Path) = %Bruce Mutton 2010.06.20 for Therion 5.3.8 T:=identity; thclean Path; pickup PenD; if known colour_sump_bg: thfill Path withcolor colour_sump_bg; else: thfill Path withcolor 0.7white; fi; thfill Path withpattern pattern_sump; %%thdraw Path; %outline, not needed as area drawn is defined by line border anyway %and border can be made invisible with subtype invisible where water meets sump in elevation enddef; endcode

**Code to define custom line rope symbol**

code metapost #submitted by Christian Jackson Nov2011 #modified for colour or black and white Bruce Mutton Nov2011 def l_u_rope (expr P) = T:=identity; pickup pensquare scaled (1.0*u/10); if known colour_rope: thdraw P withcolor colour_rope; else: thdraw P withcolor 0.1black+0.5white; fi; pickup PenC; thdraw P dashed dashpattern(on 1bp off 2bp on 1bp off 2bp); enddef; initsymbol("l_u_rope") def l_u_rope_legend = l_u_rope(((.2,.2) -- (.8,.8)) inscale) enddef; endcode

Need to add next line to all thconfig files to define legend text for the new custom rope symbol

text en "line u:rope" "rope" #text to appear in legend

**Code to make full colour symbols**

Here is a layout where you can define the colours you would like to use with the above code when you don't want a black and white map. (The groups of the statements in the 'code metapost' block are the ones that work with the code above).

I have not included any opacity statements in here, but perhaps it would be a good idea. The degree of opacity that works well for black and white outputs seems to be quite different to that which works for colour outputs.

layout LayoutColourSymbols #Still experimental (Dec 2011) and as per the comments in the code below, many of the default #'symbol-colour' statements do not work as I would like. The custom metapost #components work fine however. #affects colour symbol linework but not labels and not fills symbol-colour point station [54 7 60] #purple[54 7 60] #seems to affect +s, flag symbols and station text #survey cave symbol-colour group cave-centreline [35 16 16] # brown [35 16 16] # red brown [50 0 0] symbol-colour point cave-station [35 16 16] #ineffective? #symbol-colour point station-name [0 100 0] #survey surface symbol-colour group surface-centreline [54 74 29] # green [54 74 29] symbol-colour point surface-station [54 74 29] #ineffective? symbol-colour point flag:entrance [54 74 29] #ineffective? #magenta symbol-colour group equipment [80 0 40] # magenta [80 0 40] #dark blue # symbol-colour group water [22 22 95] # this breaks custom water definitions symbol-colour point water-flow [22 22 95] symbol-colour line water-flow [22 22 95] symbol-colour point water [22 22 95] # inconsistent? # symbol-colour area sump [22 22 95] # this breaks custom water definitions #light blue # symbol-colour area water [86 100 100] # this breaks custom water definitions #define colours for redefined water point & area code metapost %these colours affect fills, not the linework !color colour_water_bg; %! forces interpretation as metapost colour_water_bg := (0.86,1,1); %light blue !color colour_sump_bg; %! forces interpretation as metapost colour_sump_bg := (.22,.22,.95); %dark blue %these colours affect the linework !color colour_rope; %! forces interpretation as metapost colour_rope := (0.35,0.75,1.0); %blue %this colour for entrance symbol (not point station flag entrance) !color colour_entrance; %! forces interpretation as metapost colour_entrance := (0.54,0.74,0.29); endcode endlayout LayoutColourSymbols

And the 'switch' that allows you to easily toggle from black and white to colour…

Just include this line in your thconfig file (or a layout referenced from the thconfig.

copy LayoutColourSymbols #excludes labels

Comment it out when you want black and white.