I need to make several diagrams of a railway network, each of them representing different scenarios. Here is an ugly example of what I want: enter image description here And here my first attempt to reproduce it: enter image description here

As you can see, I am perfectly capable of reproducing the scenario in Tikz, but I would have to do lots of different scenarios. Can someone help me improve my code? What I need is a quick and "automatized" way of delimiting the rails (in black), the rest I can do it. What I find difficult is creating the paths with the same angles when I try to change from one side to the other and to create the end lines that represent a contact. Moreover, different scenarios have different ways of connecting both sides.




\tikzstyle{rail}=[very thick]       % m19

\draw [rail] (0,0) -- (2,0)  -- (3.5,3.8);
\draw [rail] (3.2,3.8) -- (3.8,3.8);

\draw [rail] (2.5,0) -- (5.5,0);
\draw [rail] (2.5,-0.3) -- (2.5,0.3);
\draw [rail] (5.5,-0.3) -- (5.5,0.3);

\draw [rail] (4.5,3.8) -- (6,0) -- (10.5,0);
\draw [rail] (4.2,3.8) -- (4.8,3.8);
\draw [rail] (10.5,-0.3) -- (10.5,0.3);

\node [rectangle,draw,fill=green, minimum width=1cm, minimum height=1cm] (train) at (1.5,4) {TTX2};

\draw [rail] (train) -- (9.3,4) -- (11,0) -- (13,0);
\draw [rail] (13,-0.3) -- (13,0.3);

\draw [rail](10,4) --(13,4);
\node [diamond,draw,fill=yellow] at (7.5,4) {};

\node [draw] (zone2) at (9,5.5) {Zone 2};
\draw [rail] (zone2) -- (11,5.5) -- (11.6,4.2);
\draw [rail] (11.3,4.2) -- (11.9,4.2);


  • A couple of suggestions: for the joins (I mean those terminating bars) try defining a new arrow head - though it might not be possible to make the arrow head an "absolute" angle so this might not work. For the angles, use polar coordinates. Sep 25, 2012 at 13:24
  • I have no idea of how to define an arrow. I tried using polar coordinates, but I didn't get it... Sorry for my ignorance! Sep 25, 2012 at 13:27
  • Is the "non-right-angle" bending neccessary? I think it would be much easier if that wasn't the case. Sep 25, 2012 at 16:02
  • Yes, it would me much easier, but it is necessary, it represents the connection that allows a train to go from one rail side to the other. Sep 25, 2012 at 16:07
  • Just an update, I have substantially improved my code and I think that I'll be able to provide a complete answer soon enough. Thank you for your guidelines. Sep 26, 2012 at 11:09

2 Answers 2


I defined two LaTeX macros for the arrow-like endings:

\newcommand*{\railWEend}{+ (-.3,0) -- + (.3,0) + (0,0)}
\newcommand*{\railNSend}{+ (0,.3) -- + (0,-.3) + (0,0)}

They essentially draw a .6cm long line in either north-south or west-east direction. See the full example below how they are used.

The accident diamond is put directly in the path that draws the main line. Notice the pos=.75 key. The decorations.pathreplacing library is used for the brace.




\tikzstyle{rail}=[very thick]

\newcommand*{\railWEend}{+ (-.3,0) -- + (.3,0) + (0,0)}
\newcommand*{\railNSend}{+ (0,.3) -- + (0,-.3) + (0,0)}


\draw [rail] (0,0) -- (2,0)  -- (3.5,3.8) \railWEend;

\draw [rail] (2.5,0) \railNSend -- (5.5,0) \railNSend;

\draw [rail] (4.5,3.8) \railWEend -- (6,0) -- (10.5,0) \railNSend;

\draw [decoration=brace,decorate,thick,yshift=5mm] (6,0) -- (10.5,0) node [pos=.5,above=1mm] {Maintenance zone};

\node [rectangle,draw,fill=green, minimum width=1cm, minimum height=1cm] (train) at (1.5,4) {TTX2};

\draw [rail] (train) -- node [accident,pos=.75] (acc1) {} (9.3,4) -- (11,0) -- (13,0) \railNSend;

\draw [rail](10,4) --(13,4);

\node [draw] (zone2) at (9,5.5) {Zone 2};
\draw [rail] (zone2) -- (11,5.5) -- (11.6,4.2) \railWEend;

\draw [-triangle 45,green!50!black,line width=2.5\pgflinewidth] (train) -- (acc1);



Output of code

Further annotations

I myself tried to write my own macro to design a railway network in TikZ (especially signals).
I defined a few commands and lengths that save distances or auxiliary values. I had different macros for the base of a signal (that is the same for every signal), for the top part and its name that appears near the base.

I quickly gave up because when it comes to complicated signals that have optional information (speed, direction, …) the code would have become very complex. There also already exist shapes/templates for WYSIWYG solutions like Microsoft's Visio.

I would advise you to define rules (or derive them for your technical sector of work), to follow them and use as few as possible absolute coordinates.

  • I like your solution. I grab some of your ideas for my final diagrams. Thank you very much! Sep 25, 2012 at 19:48

I found a workaround to the problem. First, I define a macro with the set of coordinates of interest for the diagram. Then I created a macro that puts an invisible circle in a given point \limitCirc. This circle is then intersected with the line that has a "bump" and creates a coordinate \limitInter. Finally, I use this coordinate to create the line and I make use of the macro \railWEend and \railNSend created by @Qrrbrbirlbel. For the signals, I used tikz-timing package to create the "wave".

Here is the output of one of the scenarios: enter image description here


% ===================================
% ===================================



\tikzstyle{rail}=[ultra thick]
\tikzstyle{movement}=[green!50!black,line width=2.5\pgflinewidth]
\tikzstyle{ttx}=[rectangle,draw,fill=green!30, minimum width=1cm, minimum height=0.6cm]
\tikzstyle{ter}=[rectangle,draw,fill=blue!30,minimum width=1cm, minimum height=0.6cm]

    node[inner sep=2pt,rectangle,rounded corners,draw,fill=white,thin]%
    {\tikz \draw[fill=#1] circle (4pt);}
    \draw[semithick] (#1)--++(0,0.5)--++(0.7,0)\feu{red};
    \draw[semithick] (#1)--++(0,-0.5)\feu{green}--++(-0.7,0)%
    node[inner sep=2pt,rectangle,rounded corners,draw,fill=white,thin]%
    {\tikz \timing[timing/slope=0.5,thick] {HlL};};
\newcommand*{\railWEend}{+ (-.3,0) -- + (.3,0) + (0,0)}
\newcommand*{\railNSend}{+ (0,.3) -- + (0,-.3) + (0,0)}
    \draw (12.5,4.2)\railWEend--++(-0.45,1)--++(-0.5,0)
    node[draw,anchor=east,thin] {Zone 2};
    \draw (7.5,-0.2)\railWEend--++(0.45,-1.3)--++(0.5,0)
    node[draw,anchor=west,thin] {Zone 3};
    \draw [decoration=brace,decorate,thick,yshift=-5mm] (9.5,4) -- (3.5,4) node         [pos=.42,below=1mm] {\textbf{Protected zone} $\approx 10km$};
    \draw [decoration=brace,decorate,thick,yshift=5mm] (2.35,0) -- (10.65,0) node [pos=.7,above=1mm] {\textbf{Maintenance zone} $\approx 10km$};

\newcommand{\limitCirc}[1]{\node[circle,minimum width=0.5cm] (l#1) at (#1) {};}
\newcommand{\limitInter}[2]{    %
    \coordinate(i#1) at (intersection 1 of l#1 and #1--#2);
    \coordinate(i#2) at (intersection 1 of l#2 and #2--#1);
    \coordinate (10) at (0,4);
    \coordinate (1a) at (3.5,4);
    \coordinate (1b) at (4.5,4);
    \coordinate (1c) at (9.5,4);
    \coordinate (1d) at (14,4);
    \coordinate (1e) at (13.5,4);

    \coordinate (20) at (0,0);
    \coordinate (2a) at (2,0);
    \coordinate (2b) at (6,0);
    \coordinate (2c) at (11,0);
    \coordinate (2d) at (13,0);
    \coordinate (2e) at (12,0);

     \node[anchor=west,draw] (head2) at (2d) {Head 2};
    \draw [->,thick](14.5,-0.5) -- (13,-0.5);
    \node[anchor=east,draw] (head1) at (10) {Head 1};
    \draw [->,thick](-1.5,4.5) -- (0,4.5);

 % ============= scenario 5 ================


    \draw[rail]  (i1a)\railWEend -- (2a) -- (20);   

    \draw[rail]  (i2a)\railNSend -- (i2b)\railNSend;

    \draw[rail]  (1c) -- (2c)--(head2); 

    \draw[rail]  (i1e)\railWEend -- (i2e)\railWEend;    

    \draw[rail]  (i1b)\railWEend -- (2b) -- (i2c)\railNSend;
    \draw[rail] (1c) -- (1d);

    \node[ttx] (ttx2)   at (1.5,4) {TTX2};
    \node[ter,rotate=-70] (ter1)   at (10.2,2) {TER};
    \node[star,star points=10, star point ratio=2.25,fill=yellow,draw] (acci)  at (7.5,4) {};

    \draw[rail]  (ttx2)--(head1);   
    \draw [-triangle 45,movement] (ttx2) -- (acci);
    \draw [-triangle 45,movement,blue] (ter1) -- (1c)--(acci);


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .