%% tikzlibrarytrainmap.code.tex
%% =========================================================================
%% trainmap -- core TikZ library for drawing schematic railway / transit maps
%%             (in the style of FGC / Rodalies line diagrams).
%%
%% This file contains the actual implementation. It is loaded by
%%     \usetikzlibrary{trainmap}
%% and the LaTeX wrapper `trainmap.sty' calls that for you when you write
%%     \usepackage{trainmap}
%%
%% Copyright (C) 2026 Pol Sardà Palla <psardapalla48@gmail.com>
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License, version 1.3c or (at your option) any later
%% version. See LICENSE for the full text. Maintainer: Pol Sardà Palla.
%% =========================================================================

% TikZ libraries used internally:
%   calc         -> coordinate arithmetic, e.g. ($(a)+(0,1)$)
%   arrows.meta  -> nicer arrow tips (available to the user)
%   bending      -> arrow tips that bend along curved paths
\usetikzlibrary{calc,arrows.meta,bending}

% =========================================================================
% 1. COLOUR PALETTE
%    Official line colours of Rodalies de Catalunya and FGC (hex values).
%    You may of course use any xcolor colour (red, blue!60!black, ...).
% =========================================================================
% --- Rodalies de Catalunya ---
\definecolor{tmR1}{HTML}{4499D4}    % R1  light blue
\definecolor{tmR2}{HTML}{009900}    % R2  green
\definecolor{tmR2N}{HTML}{99C83E}   % R2 Nord  lime green
\definecolor{tmR2S}{HTML}{00642E}   % R2 Sud   dark green
\definecolor{tmR3}{HTML}{FF131A}    % R3  red
\definecolor{tmR4}{HTML}{FF9221}    % R4  orange
\definecolor{tmR7}{HTML}{BD7DB5}    % R7  lilac
\definecolor{tmR8}{HTML}{9B1987}    % R8  purple / magenta
\definecolor{tmR11}{HTML}{0064A5}   % R11 dark blue
\definecolor{tmR12}{HTML}{FFDC00}   % R12 yellow
\definecolor{tmR13}{HTML}{E52E87}   % R13 fuchsia pink
\definecolor{tmR14}{HTML}{675199}   % R14 violet
\definecolor{tmR15}{HTML}{9A8A76}   % R15 beige grey / brown
\definecolor{tmR16}{HTML}{AF0036}   % R16 maroon
\definecolor{tmR17}{HTML}{E97300}   % R17 dark orange
\definecolor{tmRL1}{HTML}{6B8E23}   % RL1 olive green
\definecolor{tmRL2}{HTML}{32CD32}   % RL2 bright lime green
\definecolor{tmRG1}{HTML}{007DC3}   % RG1 cyan blue
\definecolor{tmRT1}{HTML}{35BDB2}   % RT1 turquoise
\definecolor{tmRT2}{HTML}{DC87B9}   % RT2 light pink
% --- FGC, Barcelona-Valles line ---
\definecolor{tmL6}{HTML}{847DC6}    % L6  violet
\definecolor{tmL7}{HTML}{AE6118}    % L7  brown
\definecolor{tmL12}{HTML}{B6B3E1}   % L12 very light lilac
\definecolor{tmS1}{HTML}{F47216}    % S1  orange
\definecolor{tmS2}{HTML}{59C134}    % S2  green
% --- FGC, Llobregat-Anoia line ---
\definecolor{tmL8}{HTML}{E659B4}    % L8  pink / magenta
\definecolor{tmR5}{HTML}{4FC4BB}    % R5  turquoise
\definecolor{tmR50}{HTML}{007D9B}   % R50 petrol blue
\definecolor{tmR6}{HTML}{9EA1A6}    % R6  grey
\definecolor{tmR60}{HTML}{565A5C}   % R60 dark grey

% =========================================================================
% 2. CONFIGURATION KEYS  (pgfkeys, namespace /trainmap/)
%    Every key can be set globally (on the environment) or locally (in the
%    optional argument of an individual command).
% =========================================================================
\pgfkeys{
  /trainmap/.is family, /trainmap/.cd,
  % --- Tracks / lines --------------------------------------------------
  line color/.initial=black,        % default colour of a single track
  track width/.initial=2pt,         % stroke width of a track
  % --- Map style -------------------------------------------------------
  mode/.initial=fgc,                % fgc | rodalies (see the manual)
  line code/.initial={},            % single-line code drawn at the two ends
                                    %   (rodalies mode); auto-filled from the
                                    %   first \addterminal if left empty
  % --- Standard stations ----------------------------------------------
  station color/.initial=black,     % colour of the perpendicular tick mark
  station width/.initial=1.8pt,     % stroke width of the tick mark
  % --- Terminal / head stations ---------------------------------------
  terminal size/.initial=8pt,       % diameter of the terminal disc
  terminal border/.initial=1.4pt,   % border width of the terminal disc
  badge color/.initial=black,       % background colour of the line badge
  % --- Interchange stations (capsules) --------------------------------
  capsule width/.initial=12pt,      % outer width of the interchange capsule
  capsule inner/.initial=8pt,       % inner (white) width of the capsule
  capsule color/.initial=black,     % border colour of the capsule
  % --- Geometry of the running route ----------------------------------
  station step/.initial=1.6,        % horizontal distance between stations (cm)
  track sep/.initial=0.16,          % vertical gap between parallel tracks (cm)
  % --- Serpentine wrapping (for long lines) ---------------------------
  max width/.initial=0,             % wrap to a new row past this x (cm); 0 = off
  row sep/.initial=2.6,             % vertical distance between wrapped rows (cm)
  % --- Station labels --------------------------------------------------
  label angle/.initial=45,          % rotation of the label text (degrees)
  label position/.initial=above,    % above | below  (label over or under track)
  % --- Correspondences -------------------------------------------------
  corr/.initial={},                 % list "CODE/colour, CODE/colour, ..." of
                                    %   connecting lines, shown as small
                                    %   coloured chips below the station
  % --- Internal --------------------------------------------------------
  name/.initial={},                 % optional id -> creates named coordinates
}

% =========================================================================
% 3. TikZ STYLES DERIVED FROM THE KEYS
% =========================================================================
\tikzset{
  % A standard track: configurable width, rounded ends.
  trainmap track/.style={
    line width=\pgfkeysvalueof{/trainmap/track width},
    line cap=round,
  },
  % The perpendicular tick mark of a standard station.
  trainmap station/.style={
    line width=\pgfkeysvalueof{/trainmap/station width},
    line cap=round,
    color=\pgfkeysvalueof{/trainmap/station color},
  },
  % The filled disc of a terminal / head station.
  trainmap terminal/.style={
    circle, draw,
    line width=\pgfkeysvalueof{/trainmap/terminal border},
    minimum size=\pgfkeysvalueof{/trainmap/terminal size},
    inner sep=0pt,
    fill=white,
  },
  % Rotated label placed ABOVE the track (reads towards the upper right).
  % `align=left' makes manual line breaks (\\) work inside station names.
  trainmap label above/.style={
    rotate=\pgfkeysvalueof{/trainmap/label angle},
    anchor=south west,
    font=\footnotesize,
    align=left,
    inner sep=2pt,
  },
  % Rotated label placed BELOW the track (reads towards the lower left).
  trainmap label below/.style={
    rotate=\pgfkeysvalueof{/trainmap/label angle},
    anchor=north east,
    font=\footnotesize,
    align=left,
    inner sep=2pt,
  },
  % Line badge: rounded box with the line code in white (fgc mode).
  trainmap badge/.style={
    rounded corners=1.5pt,
    inner xsep=3.5pt, inner ysep=1.5pt,
    font=\scriptsize\bfseries,
    align=center,
    text=white,
  },
  % Square line-code plate drawn at the ends of a single line (rodalies mode).
  trainmap linecode/.style={
    rectangle, draw=none,
    inner sep=3pt, minimum height=13pt,
    font=\footnotesize\bfseries,
    align=center,
    text=white,
  },
  % Small correspondence chip: a coloured square with the connecting line code.
  trainmap chip/.style={
    rectangle, draw=none,
    inner sep=1.5pt, minimum width=9pt, minimum height=9pt,
    font=\tiny\bfseries,
    align=center,
    text=white,
  },
}

% =========================================================================
% 4. INTERNAL STATE  (the running "cursor")
% -------------------------------------------------------------------------
% \tm@x       current horizontal position of the cursor (number, cm)
% \tm@first   flag "1" until the first station has been placed
% \tm@lanes   list "y/colour, y/colour, ..." of the parallel trunk tracks
% \tm@ttop    top y of the trunk band     (relative, before row mapping)
% \tm@tbot    bottom y of the trunk band   (relative, before row mapping)
% \tm@center  vertical centre of the trunk band  (for serpentine mirroring)
% \tm@dir     travelling direction: +1 (rightwards) or -1 (leftwards)
% \tm@sign    parity of the current row: +1 (normal) or -1 (mirrored)
% \tm@rowbase y of the current row's centre (0, -rowsep, -2*rowsep, ...)
% \tmlastx    (public) x of the last placed station -> anchor for branches
% \tmlasty    (public) y (centre) of the last placed station
%
% Row mapping (supports the serpentine layout).  The absolute y of a trunk
% track stored as `l' is:
%       y(l) = (rowbase + center) + sign * (l - center)
% On row 0 this reduces to y = l, so non-wrapped maps keep their absolute
% coordinates and hand-placed branch endpoints stay valid.  On mirrored rows
% the track order flips, which is exactly what a parallel U-turn requires so
% that the tracks nest concentrically without crossing.
% =========================================================================
\def\tm@x{0}
\def\tm@first{1}
\def\tm@lanes{0/black}
\def\tm@ttop{0}
\def\tm@tbot{0}
\def\tm@center{0}
\def\tm@dir{1}
\def\tm@sign{1}
\def\tm@rowbase{0}
\def\tm@mode{fgc}
\def\tm@linecode{}
\def\tm@lanecolor{black}
\def\tm@rodalies{rodalies}   % constant used for \ifx comparisons

% ---- \settrunk{<y/colour list>} -----------------------------------------
% Declare the parallel tracks that make up the common trunk, and compute the
% band extent and centre.  May be called again at any time to add or remove
% tracks (e.g. when a line branches off and leaves the trunk).
%
%   \settrunk{0/tmS2, 0.18/tmS1, 0.36/tmL7, 0.54/tmL6}
\newcommand{\settrunk}[1]{%
  \gdef\tm@lanes{#1}%
  \def\tm@mina{1000}\def\tm@maxb{-1000}%
  \foreach \ly/\lc in {#1}{%
    \pgfmathparse{min(\tm@mina,\ly)}\xdef\tm@mina{\pgfmathresult}%
    \pgfmathparse{max(\tm@maxb,\ly)}\xdef\tm@maxb{\pgfmathresult}%
    \xdef\tm@lanecolor{\lc}%   remember a track colour (for the end plates)
  }%
  \global\let\tm@tbot\tm@mina
  \global\let\tm@ttop\tm@maxb
  \pgfmathsetmacro{\tm@cc}{(\tm@mina+\tm@maxb)/2}\xdef\tm@center{\tm@cc}%
}

% ---- \tm@drawsegment{<x1>}{<x2>} : draw one trunk segment on current row --
\newcommand{\tm@drawsegment}[2]{%
  \pgfmathsetmacro{\tm@rcs}{\tm@rowbase + \tm@center}%
  \foreach \ly/\lc in \tm@lanes {%
    \pgfmathsetmacro{\tm@yy}{\tm@rcs + \tm@sign*(\ly - \tm@center)}%
    \draw[trainmap track, draw=\lc] (#1,\tm@yy) -- (#2,\tm@yy);%
  }%
}

% ---- \tm@dowrap : perform a serpentine U-turn to the next row ------------
% Draws, for every trunk track, a concentric half-loop connecting the end of
% the current row to the start of the row below, then flips direction and
% row parity.  The half-loops nest automatically because their radii grow
% with the track's distance from the band centre.
\newcommand{\tm@dowrap}{%
  \pgfmathsetmacro{\tm@rs}{\pgfkeysvalueof{/trainmap/row sep}}%
  \pgfmathsetmacro{\tm@nb}{\tm@rowbase - \tm@rs}%       % next row base (below)
  \pgfmathsetmacro{\tm@ns}{-\tm@sign}%                  % next row parity
  \pgfmathsetmacro{\tm@rcA}{\tm@rowbase + \tm@center}%  % this row centre (abs)
  \pgfmathsetmacro{\tm@rcB}{\tm@nb + \tm@center}%       % next row centre (abs)
  \foreach \ly/\lc in \tm@lanes {%
    \pgfmathsetmacro{\tm@yA}{\tm@rcA + \tm@sign*(\ly - \tm@center)}%
    \pgfmathsetmacro{\tm@yB}{\tm@rcB + \tm@ns*(\ly - \tm@center)}%
    \ifdim \tm@dir pt>0pt
      % travelling right -> loop on the right-hand side
      \draw[trainmap track, draw=\lc]
        (\tm@x,\tm@yA) to[out=0,in=0,looseness=1.35] (\tm@x,\tm@yB);%
    \else
      % travelling left -> loop on the left-hand side
      \draw[trainmap track, draw=\lc]
        (\tm@x,\tm@yA) to[out=180,in=180,looseness=1.35] (\tm@x,\tm@yB);%
    \fi
  }%
  \xdef\tm@rowbase{\tm@nb}%
  \pgfmathsetmacro{\tm@nsx}{-\tm@sign}\xdef\tm@sign{\tm@nsx}%
  \pgfmathsetmacro{\tm@ndx}{-\tm@dir}\xdef\tm@dir{\tm@ndx}%
}

% ---- \tm@advance : move the cursor to the next station ------------------
% On the first station: stay at x=0.  Otherwise move by `station step' in the
% current direction, wrapping to a new row first if the move would exceed
% `max width' (when serpentine wrapping is enabled).  Finally compute the
% row-aware geometry used to draw the station:
%   \tm@ytop \tm@ybot  extent of the trunk band on this row
%   \tm@a \tm@b        the tick mark endpoints (band extent + margin)
%   \tm@mid           vertical centre (disc / capsule position)
\newcommand{\tm@advance}{%
  \ifnum\tm@first=1
    \gdef\tm@first{0}%
  \else
    \pgfmathsetmacro{\tm@mw}{\pgfkeysvalueof{/trainmap/max width}}%
    \pgfmathsetmacro{\tm@newx}{\tm@x + \tm@dir*(\pgfkeysvalueof{/trainmap/station step})}%
    \ifdim \tm@mw pt>0pt
      % serpentine wrapping enabled -> test whether we must turn
      \pgfmathparse{((\tm@dir>0)&&(\tm@newx>\tm@mw))||((\tm@dir<0)&&(\tm@newx<0))}%
      \ifdim \pgfmathresult pt>0.5pt
        \tm@dowrap                       % turn; x stays at the row edge
      \else
        \tm@drawsegment{\tm@x}{\tm@newx}%
        \xdef\tm@x{\tm@newx}%
      \fi
    \else
      \tm@drawsegment{\tm@x}{\tm@newx}%
      \xdef\tm@x{\tm@newx}%
    \fi
  \fi
  \global\let\tmlastx\tm@x
  \pgfmathsetmacro{\tm@rc}{\tm@rowbase + \tm@center}%
  \pgfmathsetmacro{\tm@ytop}{\tm@rc + \tm@sign*(\tm@ttop - \tm@center)}%
  \pgfmathsetmacro{\tm@ybot}{\tm@rc + \tm@sign*(\tm@tbot - \tm@center)}%
  \pgfmathsetmacro{\tm@a}{min(\tm@ytop,\tm@ybot)-0.16}%
  \pgfmathsetmacro{\tm@b}{max(\tm@ytop,\tm@ybot)+0.16}%
  \pgfmathsetmacro{\tm@mid}{(\tm@ytop+\tm@ybot)/2}%
  \global\let\tmlasty\tm@mid
}

% ---- \tm@namecoord : expose named coordinates if name= was given --------
\newcommand{\tm@namecoord}{%
  \pgfkeysgetvalue{/trainmap/name}{\tm@nm}%
  \ifx\tm@nm\@empty\else
    \coordinate (\tm@nm)      at (\tm@x,\tm@ytop);%   top track
    \coordinate (\tm@nm-bot)  at (\tm@x,\tm@ybot);%   bottom track
    \coordinate (\tm@nm-mid)  at (\tm@x,\tm@mid);%    band centre
  \fi
}

% ---- \tm@drawcorr : draw correspondence chips below the station ---------
% Reads the `corr' key (list "CODE/colour, ...") and stacks a small coloured
% square per connecting line just beneath the station.
\newcommand{\tm@drawcorr}{%
  \pgfkeysgetvalue{/trainmap/corr}{\tm@cl}%
  \ifx\tm@cl\@empty\else
    \foreach \tm@cc/\tm@ccol [count=\tm@ci from 0] in \tm@cl {%
      \node[trainmap chip, fill=\tm@ccol, anchor=north]
           at (\tm@x, {\tm@a - 0.18 - \tm@ci*0.36}) {\tm@cc};%
    }%
  \fi
}

% =========================================================================
% 5. ENVIRONMENT
% =========================================================================
% \begin{trainmap}[<keys>] ... \end{trainmap}
% Wraps a tikzpicture and resets the cursor / trunk state for this map.
\newenvironment{trainmap}[1][]{%
  \begingroup
  \gdef\tm@x{0}%
  \gdef\tm@first{1}%
  \gdef\tm@lanes{0/black}%
  \gdef\tm@ttop{0}\gdef\tm@tbot{0}\gdef\tm@center{0}%
  \gdef\tm@dir{1}\gdef\tm@sign{1}\gdef\tm@rowbase{0}%
  \gdef\tm@lanecolor{black}%
  \global\let\tmlastx\tm@x
  \global\let\tmlasty\tm@x
  \pgfkeys{/trainmap/.cd,#1}%
  \xdef\tm@mode{\pgfkeysvalueof{/trainmap/mode}}%
  \xdef\tm@linecode{\pgfkeysvalueof{/trainmap/line code}}%
  \begin{tikzpicture}[x=1cm,y=1cm]%
}{%
  % In rodalies mode, close the single line with a square plate at its tail.
  \ifx\tm@mode\tm@rodalies
    \ifx\tm@linecode\@empty\else
      \pgfmathsetmacro{\tm@tx}{\tmlastx + \tm@dir*0.6}%
      \draw[trainmap track, draw=\tm@lanecolor]
           (\tmlastx,\tmlasty) -- (\tm@tx,\tmlasty);%
      \ifdim \tm@dir pt>0pt
        \node[trainmap linecode, fill=\tm@lanecolor, anchor=west]
             at (\tm@tx,\tmlasty) {\tm@linecode};%
      \else
        \node[trainmap linecode, fill=\tm@lanecolor, anchor=east]
             at (\tm@tx,\tmlasty) {\tm@linecode};%
      \fi
    \fi
  \fi
  \end{tikzpicture}%
  \endgroup
}

% ---- \tm@rodhead : draw the head plate at the very first station --------
% In rodalies mode the single line begins next to a square plate carrying the
% line code, placed to the left of the first station. #1 is the "was first"
% flag captured before \tm@advance.
\newcommand{\tm@rodhead}[1]{%
  \ifx\tm@mode\tm@rodalies
    \ifnum#1=1
      \ifx\tm@linecode\@empty\else
        \pgfmathsetmacro{\tm@hx}{\tm@x - 0.6}%
        \draw[trainmap track, draw=\tm@lanecolor]
             (\tm@hx,\tm@mid) -- (\tm@x,\tm@mid);%
        \node[trainmap linecode, fill=\tm@lanecolor, anchor=east]
             at (\tm@hx,\tm@mid) {\tm@linecode};%
      \fi
    \fi
  \fi
}

% =========================================================================
% 6. PUBLIC API -- STATIONS
% =========================================================================

% ---- \addstation[<keys>]{<name>} ----------------------------------------
% Standard station: a perpendicular tick mark crossing every parallel track
% of the trunk, plus a rotated label.  Handy keys:
%   name=<id>            create coordinates (<id>), (<id>-mid), (<id>-bot)
%   label position=below put the label under the track
%   station step=<cm>    use a custom gap before this station
\newcommand{\addstation}[2][]{%
  \begingroup
  \pgfkeys{/trainmap/.cd,#1}%
  \edef\tm@wasfirst{\tm@first}%
  \tm@advance
  \draw[trainmap station] (\tm@x,\tm@a) -- (\tm@x,\tm@b);%
  \tm@rodhead{\tm@wasfirst}%
  \tm@namecoord
  \tm@drawcorr
  \pgfkeysgetvalue{/trainmap/label position}{\tm@lp}%
  \def\tm@posabove{above}%
  \ifx\tm@lp\tm@posabove
    \node[trainmap label above] at (\tm@x,\tm@b) {#2};%
  \else
    \node[trainmap label below] at (\tm@x,\tm@a) {#2};%
  \fi
  \endgroup
}

% ---- \addterminal[<keys>]{<name>}{<line code>} --------------------------
% Terminal / head station: a filled disc in the line colour, the name in
% bold, and a badge with the line code underneath.  Choose the colour with
% badge color=<colour>.
\newcommand{\addterminal}[3][]{%
  \begingroup
  \pgfkeys{/trainmap/.cd,#1}%
  % In rodalies mode, adopt the first terminal's code as the line code
  % (used for the square plates at both ends) unless one was set explicitly.
  \ifx\tm@mode\tm@rodalies
    \ifx\tm@linecode\@empty \xdef\tm@linecode{#3}\fi
  \fi
  \edef\tm@wasfirst{\tm@first}%
  \tm@advance
  \pgfkeysgetvalue{/trainmap/badge color}{\tm@bc}%
  \node[trainmap terminal, fill=\tm@bc] at (\tm@x,\tm@mid) {};%
  \tm@rodhead{\tm@wasfirst}%
  \tm@namecoord
  \tm@drawcorr
  \node[trainmap label above, font=\footnotesize\bfseries]
       at (\tm@x,\tm@b) {#2};%
  % The line code goes below the disc only in fgc mode (several lines shown);
  % in rodalies mode the code lives on the end plates instead.
  \ifx\tm@mode\tm@rodalies\else
    \node[trainmap badge, fill=\tm@bc, anchor=north, yshift=-3pt]
         at (\tm@x,\tm@a) {#3};%
  \fi
  \endgroup
}

% ---- \addinterchange[<keys>]{<name>} ------------------------------------
% Interchange / correspondence station: a rounded capsule that visually
% groups all the parallel tracks of the trunk, with one coloured dot per
% line.  Use it where several services share a station (e.g. Sarria).
\newcommand{\addinterchange}[2][]{%
  \begingroup
  \pgfkeys{/trainmap/.cd,#1}%
  \edef\tm@wasfirst{\tm@first}%
  \tm@advance
  \tm@rodhead{\tm@wasfirst}%
  \draw[line width=\pgfkeysvalueof{/trainmap/capsule width}, line cap=round,
        color=\pgfkeysvalueof{/trainmap/capsule color}]
       (\tm@x,\tm@ytop) -- (\tm@x,\tm@ybot);%
  \draw[line width=\pgfkeysvalueof{/trainmap/capsule inner}, line cap=round,
        color=white]
       (\tm@x,\tm@ytop) -- (\tm@x,\tm@ybot);%
  \foreach \ly/\lc in \tm@lanes {%
    \pgfmathsetmacro{\tm@yy}{\tm@rowbase + \tm@center + \tm@sign*(\ly - \tm@center)}%
    \fill[color=\lc] (\tm@x,\tm@yy) circle[radius=1.8pt];%
  }%
  \tm@namecoord
  \tm@drawcorr
  \node[trainmap label above, font=\footnotesize\bfseries]
       at (\tm@x,\tm@b) {#2};%
  \endgroup
}

% =========================================================================
% 7. PUBLIC API -- TRACKS, BRANCHES AND FORKS
% -------------------------------------------------------------------------
% The <from> / <to> arguments are passed WITH their parentheses, so they may
% be explicit coordinates {(\tmlastx,0.36)}, named nodes {(sarria)} or even
% `calc' expressions {($(avtib)+(0,0.2)$)}.  This lets you freely mix the
% cursor engine with hand-placed geometry.
% =========================================================================

% ---- \track[<opts>]{<from>}{<to>}{<colour>} : straight track segment -----
\newcommand{\track}[4][]{%
  \draw[trainmap track, draw=#4, #1] #2 -- #3;%
}

% ---- \branch[<opts>]{<from>}{<to>}{<colour>} : gentle horizontal branch --
\newcommand{\branch}[4][]{%
  \draw[trainmap track, draw=#4, #1] #2 to[out=0, in=180] #3;%
}

% ---- \forkup / \forkline : branch that peels UPWARDS ---------------------
\newcommand{\forkline}[4][]{%
  \draw[trainmap track, draw=#4, #1] #2 to[out=30, in=180] #3;%
}
\newcommand{\forkup}[4][]{%
  \draw[trainmap track, draw=#4, #1] #2 to[out=30, in=180] #3;%
}

% ---- \forkdown : branch that peels DOWNWARDS -----------------------------
\newcommand{\forkdown}[4][]{%
  \draw[trainmap track, draw=#4, #1] #2 to[out=-30, in=180] #3;%
}

% ---- \joinline : a branch merging back INTO the trunk --------------------
\newcommand{\joinline}[4][]{%
  \draw[trainmap track, draw=#4, #1] #2 to[out=0, in=210] #3;%
}

\endinput
