# trainmap `trainmap` is a LaTeX + TikZ package for drawing **schematic railway and transit maps** declaratively, in the style of the FGC / Rodalies line diagrams. Instead of positioning every node by hand, you describe a line or a whole network with a small, readable set of commands — `\addstation`, `\addterminal`, `\forkup`, `\branch`, and so on — and the package takes care of the geometry.

Rodalies R7 line produced with trainmap

## Table of contents - [Features](#features) - [The two map styles (`mode`)](#the-two-map-styles-mode) - [Documentation](#documentation) - [Installation](#installation) - [Using it in your editor (TeXstudio)](#using-it-in-your-editor-texstudio) - [Quick start](#quick-start) - [Long lines: the serpentine layout](#long-lines-the-serpentine-layout) - [Command reference](#command-reference) - [Configuration keys](#configuration-keys) - [Predefined colours](#predefined-colours) - [How the engine works](#how-the-engine-works) - [Repository layout](#repository-layout) - [License](#license) ## Features - **Two map styles.** An **FGC** style that shows every line at once (with a line badge on each terminal), and a **Rodalies** style for a single line whose code is shown on a square plate at each end. Both still show interchanges. Selected with the `mode` key. - **Key–value configuration** through `pgfkeys`, all under the `/trainmap/` namespace: line colours, stroke widths, label angles and station sizes. Any key can be set once for the whole map or overridden on an individual station. - **Common trunk of parallel tracks.** Several lines can run together as a stacked bundle and then branch off or join at different heights. - **Multi-line station names.** Break a long name across lines with `\\`. - **Standard stations** drawn as a perpendicular tick crossing the whole bundle, with a rotated label (45° by default, configurable). - **Terminal / head stations** drawn as a larger filled disc, a **bold** name and a coloured **badge** carrying the line code (for example `S1`, `L6`). - **Interchange stations** drawn as a rounded capsule that groups all the parallel tracks, for stops shared by several services. - **Branches and forks** with smoothly curved diagonal connectors: `\forkup`, `\forkdown`, `\joinline`, `\branch`, `\track`. - **Automatic serpentine (snake) wrapping** for lines that are too long to fit on one row: set a maximum width and the line folds onto stacked rows joined by nested U-turns. - **Two ways to load it:** as a LaTeX package (`\usepackage{trainmap}`) or as a TikZ library (`\usetikzlibrary{trainmap}`). ## The two map styles (`mode`) The `mode` key selects how the diagram is presented. ### `mode=fgc` (default) — several lines at once Every line of the trunk is drawn. Each `\addterminal` shows a filled disc, the bold station name, and the line badge **below the disc**; interchanges are drawn as capsules. Use this when several services share the diagram (the classic FGC schematic look).

FGC-style multi-line map

Full source: [`examples/fgc_style_map.tex`](examples/fgc_style_map.tex). ### `mode=rodalies` — a single line Only one line is drawn. Its code is shown as a **square plate at each end** of the whole route, with the line starting right next to the plate — so terminals no longer carry an individual badge. Station names appear as usual and shared stops are still marked as correspondences with `\addinterchange`. The code for the end plates is taken from `line code`, or automatically from the first `\addterminal` if you do not set it. ```latex \begin{trainmap}[mode=rodalies, badge color=tmR4] \settrunk{0/tmR4} \addterminal{Sant Vicenç de Calders}{R4} % opening [R4] plate \addstation{El Vendrell} % ... \addinterchange{Barcelona Sants} % a correspondence % ... \addterminal{Manresa}{R4} % closing [R4] plate \end{trainmap} ``` Because Rodalies lines tend to be long, this mode is normally combined with the [serpentine layout](#long-lines-the-serpentine-layout). See [`examples/rodalies_r4.tex`](examples/rodalies_r4.tex) for the full R4 line. ## Documentation The full user manual is included as **[`trainmap.pdf`](trainmap.pdf)** (source: [`trainmap-doc.tex`](trainmap-doc.tex)). It covers installation, the complete command and key reference, and worked examples with rendered diagrams. ## Installation The package is made of two files that must always travel together: | File | Role | |------|------| | `trainmap.sty` | LaTeX wrapper — enables `\usepackage{trainmap}`. | | `tikzlibrarytrainmap.code.tex` | The implementation — loaded by `\usetikzlibrary{trainmap}`. | ### Option A — from CTAN (once published) `trainmap` is prepared for distribution on [CTAN](https://ctan.org). Once it is available there, install it with your TeX distribution's package manager: ```bash tlmgr install trainmap # TeX Live mpm --install=trainmap # MiKTeX (or use the MiKTeX Console) ``` Most distributions also ship it in their package repositories, so it may already be installed. After that, `\usepackage{trainmap}` just works. ### Option B — next to your document (quickest) Copy **both** files into the same folder as your `.tex` file and compile with `pdflatex`. LaTeX always searches the document's own folder first, so nothing else is required. ### Option C — install into your personal `texmf` tree (available everywhere) ```bash # 1. Find your personal texmf root kpsewhich -var-value TEXMFHOME # Linux/macOS: usually ~/texmf # Windows/MiKTeX: usually C:\Users\\AppData\Roaming\MiKTeX # 2. Create the destination folder and copy both files mkdir -p "$(kpsewhich -var-value TEXMFHOME)/tex/latex/trainmap" cp trainmap.sty tikzlibrarytrainmap.code.tex \ "$(kpsewhich -var-value TEXMFHOME)/tex/latex/trainmap/" # 3. Refresh the filename database mktexlsr # TeX Live # MiKTeX: open the MiKTeX Console -> Tasks -> Refresh file name database # (or run: initexmf --update-fndb) ``` On Windows you can copy the files manually instead of using the shell; the destination folder is `C:\Users\\AppData\Roaming\MiKTeX\tex\latex\trainmap\`. After a database refresh, `\usepackage{trainmap}` works from any document. ## Using it in your editor (TeXstudio) **Compiling.** Build with **pdfLaTeX**. In TeXstudio press **F5** (build and view) or **F6** (build only). If the default compiler is not pdfLaTeX, set it under *Options → Configure TeXstudio → Build → Default Compiler → PdfLaTeX*. **Removing the orange highlighting.** By default TeXstudio underlines any command it does not know — so `\addstation`, `\addterminal`, etc. appear in a warning colour even though the document compiles perfectly. This is only a cosmetic check in the editor, not an error. To make TeXstudio recognise the `trainmap` commands, install the bundled completion file `trainmap.cwl`: 1. In TeXstudio open *Help → Show Manual* is not needed — instead go to *Options → Configure TeXstudio → Completion* and note the user completion directory, or simply copy `trainmap.cwl` into TeXstudio's completion folder: - Windows: `C:\Users\\AppData\Roaming\texstudio\completion\user\` - Linux: `~/.config/texstudio/completion/user/` - macOS: `~/Library/Application Support/texstudio/completion/user/` 2. Restart TeXstudio. Once the file is in place and your document contains `\usepackage{trainmap}`, the commands are treated as known and the orange highlighting disappears; you also get autocompletion for the commands and their keys. ## Quick start ```latex \documentclass[border=10pt]{standalone} \usepackage{trainmap} \begin{document} % mode=rodalies -> a square [S1] plate at each end of the line \begin{trainmap}[mode=rodalies, station step=2.0, badge color=tmS1] \settrunk{0/tmS1} % a single orange track (S1) \addterminal{Pl. Espanya}{S1} % first end (sets the line code) \addstation{Magòria} \addstation{Ildefons Cerdà} \addinterchange{Sant Josep} % a correspondence / transfer \addstation[label position=below]{Gornal} \addstation{L'Hospitalet\\de Llobregat} % \\ = manual line break \addterminal{Cornellà}{S1} % last end (closing plate) \end{trainmap} \end{document} ```

Simple S1 line, Rodalies style

Full source: [`examples/simple_line.tex`](examples/simple_line.tex). ## Long lines: the serpentine layout When a line has too many stations to fit on a single row, enable **serpentine wrapping**: set `max width` (the x, in cm, at which the line should wrap) and optionally `row sep` (the vertical distance between rows). The cursor turns automatically at the edge, drawing a nested U-turn, and you keep calling `\addstation` as usual — no manual bookkeeping. ```latex \begin{trainmap}[mode=rodalies, station step=1.6, max width=20, row sep=3.8, badge color=tmR4] \settrunk{0/tmR4} \addterminal{Sant Vicenç de Calders}{R4} \addstation{El Vendrell} % ... many more stations ... \addterminal{Manresa}{R4} \end{trainmap} ```

The R4 line folded into three rows

Full source: [`examples/rodalies_r4.tex`](examples/rodalies_r4.tex) — the complete R4 line (38 stations) in Rodalies style, folded over three rows. For a bundle of several parallel tracks the U-turns nest concentrically, so the lines stay parallel and never cross. Serpentine wrapping is most useful for one or a few lines; give `row sep` enough room that the rotated labels of one row do not reach the row above. ## Command reference ### The `trainmap` environment ```latex \begin{trainmap}[] ... \end{trainmap} ``` Wraps a `tikzpicture`, fixes the drawing unit to 1 cm, and resets the internal cursor and trunk state. Any `/trainmap/` key may be given in `` as a map wide default. You can still add ordinary TikZ code (`\node`, `\draw`, `\coordinate`, …) inside the environment, which is how the examples place off-trunk terminals. ### Defining the trunk ```latex \settrunk{/, /, ...} ``` Declares the parallel tracks that currently make up the common trunk. Each entry is a vertical offset in centimetres and the colour of that track. The tracks are drawn automatically between consecutive stations. `\settrunk` may be **called again at any point** to change the active bundle — for example after a line branches away it should be dropped from the trunk, or a new line can be added. In the FGC example the trunk starts as four tracks and is reduced to three and then two as L7 and L6 leave. ### Stations | Command | What it draws | |---------|---------------| | `\addstation[]{}` | A **standard station**: a perpendicular tick crossing every track of the trunk, plus a rotated label. | | `\addterminal[]{}{}` | A **terminal / head station**: a filled disc in the badge colour and the name in bold above. In `fgc` mode a badge with `` is drawn below the disc; in `rodalies` mode there is no per-terminal badge (the code appears on the end plates instead, and the first terminal's `` becomes the line code if none was set). | | `\addinterchange[]{}` | An **interchange station**: a rounded capsule grouping all trunk tracks, with a coloured dot per line, and a bold label. | Any `` may contain `\\` to break it across several lines. Every station call **advances the cursor** by `station step` centimetres (in the current direction) before drawing, and publishes the reached position in the macros `\tmlastx` and `\tmlasty`. This is how you anchor a branch to a station: capture the value right after the call. ```latex \addstation[name=gracia]{Gràcia} \edef\gx{\tmlastx} % \gx now holds Gràcia's x coordinate ``` Passing `name=` additionally creates three reusable coordinates: `()` at the top track, `(-mid)` at the band centre, and `(-bot)` at the bottom track. Useful per-station keys: `label position=below` (label under the track), `station step=` (a custom gap before this one), `badge color=` (for terminals and interchanges). ### Tracks, branches and forks The `` and `` arguments are passed **with their parentheses**, so they accept explicit coordinates, named nodes, or `calc` expressions interchangeably: ```latex \forkup{(\gx,0.36)}{(avtib)}{tmL7} % coordinate -> named node \track{(sarria)}{($(sarria)+(2,0)$)}{tmL6} % named node -> calc expression ``` | Command | What it draws | |---------|---------------| | `\track[]{}{}{}` | A straight track segment. | | `\branch[]{}{}{}` | A gentle, near-horizontal curved branch. | | `\forkup[]{}{}{}` | A branch that peels **upwards** (alias: `\forkline`). | | `\forkdown[]{}{}{}` | A branch that peels **downwards**. | | `\joinline[]{}{}{}` | A branch **merging back** into the trunk from below. | `` is an optional list of raw TikZ options appended to the `\draw` (for example `[looseness=1.2]` or `[dashed]`). ## Configuration keys All keys live under `/trainmap/`. Set them on the environment for a map-wide default, or in a command's `[ ... ]` to override a single element. | Key | Default | Meaning | |-----|---------|---------| | `mode` | `fgc` | Map style: `fgc` (all lines, badges on terminals) or `rodalies` (single line, code on end plates). | | `line code` | (empty) | Code shown on the end plates in `rodalies` mode. If empty, it is taken from the first `\addterminal`. | | `line color` | `black` | Fallback colour of a single track. | | `track width` | `2pt` | Stroke width of a track. | | `station color` | `black` | Colour of the station tick mark. | | `station width` | `1.8pt` | Stroke width of the tick mark. | | `terminal size` | `8pt` | Diameter of the terminal disc. | | `terminal border` | `1.4pt` | Border width of the terminal disc. | | `badge color` | `black` | Background colour of the line badge. | | `capsule width` | `12pt` | Outer width of the interchange capsule. | | `capsule inner` | `8pt` | Inner (white) width of the capsule. | | `capsule color` | `black` | Border colour of the capsule. | | `station step` | `1.6` | Horizontal distance between stations (cm). | | `track sep` | `0.16` | Suggested vertical gap between parallel tracks (cm). | | `max width` | `0` | Wrap to a new row once the cursor passes this x (cm). `0` disables wrapping. | | `row sep` | `2.6` | Vertical distance between wrapped rows (cm). | | `label angle` | `45` | Rotation of the station labels (degrees). | | `label position` | `above` | `above` or `below` — label over or under the track. | ## Predefined colours The package defines the official line colours of **Rodalies de Catalunya** and **FGC**; you can also use any `xcolor` colour such as `red` or `blue!60!black`. **Rodalies de Catalunya** | Name | Line | Name | Line | Name | Line | |------|------|------|------|------|------| | `tmR1` | R1 | `tmR8` | R8 | `tmR16` | R16 | | `tmR2` | R2 | `tmR11` | R11 | `tmR17` | R17 | | `tmR2N` | R2 Nord | `tmR12` | R12 | `tmRL1` | RL1 | | `tmR2S` | R2 Sud | `tmR13` | R13 | `tmRL2` | RL2 | | `tmR3` | R3 | `tmR14` | R14 | `tmRG1` | RG1 | | `tmR4` | R4 | `tmR15` | R15 | `tmRT1` | RT1 | | `tmR7` | R7 | | | `tmRT2` | RT2 | **FGC** — Barcelona-Vallès: `tmL6`, `tmL7`, `tmL12`, `tmS1`, `tmS2`. Llobregat-Anoia: `tmL8`, `tmR5`, `tmR50`, `tmR6`, `tmR60`. ### Correspondences Any station accepts a `corr` key listing the connecting lines as `CODE/colour` pairs; each becomes a small coloured chip stacked beneath the station (as on the R7 map at the top of this page): ```latex \addstation[corr={R3/tmR3, R4/tmR4}]{Montcada Bifurcació} ``` ## How the engine works `trainmap` keeps a small amount of state — a horizontal **cursor**, a travelling **direction**, a **row** index and the list of trunk tracks. Each `\add...` call advances the cursor, draws the trunk segment(s) leading up to it, and then draws the station symbol and label. Coordinates are placed with `pgfmath`, so the vertical positions of the tracks, the tick extents and the label anchors are all derived from the keys rather than hard-coded. For the serpentine layout the absolute y of a track stored as `l` is ``` y(l) = (rowbase + center) + sign * (l - center) ``` On the first row this reduces to `y = l`, so ordinary maps keep their absolute coordinates (hand-placed branch endpoints remain valid). On a wrapped row the `sign` flips, which mirrors the track order — exactly what a parallel U-turn needs so the connecting half-loops nest concentrically instead of crossing. ## Repository layout ``` trainmap/ ├── trainmap.sty # LaTeX wrapper ├── tikzlibrarytrainmap.code.tex # Core TikZ library (the implementation) ├── trainmap.cwl # TeXstudio/TeXworks completion file ├── trainmap-doc.tex # User manual (source) ├── trainmap.pdf # User manual (compiled) ├── examples/ │ ├── simple_line.tex # Rodalies style: one line, end plates │ ├── rodalies_r7.tex # Rodalies style + correspondences (the R7 line) │ ├── fgc_style_map.tex # FGC style: common trunk, branches, interchange │ └── rodalies_r4.tex # Rodalies style + serpentine: the full R4 line ├── docs/ │ ├── preview_simple_line.png │ ├── preview_rodalies_r7.png │ ├── preview_fgc_style_map.png │ └── preview_rodalies_r4.png ├── README.md ├── LICENSE # LaTeX Project Public License v1.3c └── .gitignore ``` To build every example locally: ```bash cd examples pdflatex simple_line.tex pdflatex rodalies_r7.tex pdflatex fgc_style_map.tex pdflatex rodalies_r4.tex ``` ## License Released under the **LaTeX Project Public License (LPPL), version 1.3c** or (at your option) any later version — see [`LICENSE`](LICENSE). This is the standard license for LaTeX packages and is the license under which `trainmap` is distributed on CTAN. The package has LPPL maintenance status *maintained*; the Current Maintainer is **Pol Sardà Palla**.