[Tex/LaTex] Tikz: Drawing railway tracks

tikz-pgf

I like to draw a double line such that the gap between the two lines is transparent. My purpose is to draw railway tracks:

 \documentclass[tikz]{standalone}

 \tikzstyle{track}=[
   postaction={draw=gray,densely dashed,line width=14pt},
   postaction={draw=black,double distance=8pt,line width=2pt},
   postaction={draw=gray,densely dashed,line width=8pt},]

 \begin{document}

 \begin{tikzpicture}

 \draw[track] (-5,27) to[out=  0,in=180] ( 5,33) 
                      to[out=  0,in= 90] ( 7,25) 
                      to[out=270,in=  0] (-5,27);

 \draw[track] (-4,10) to (0,10) to[out=  0,in=270] (4,16);
 \draw[track] (12,10) to (8,10) to[out=180,in=270] (4,16) to (4,20);

 \draw[track] (-4,0) to (12,0);

 \draw[track] (0,0) to[out=  0,in=270] (3,2) 
                    to[out= 90,in=270] (1,4)
                    to[out= 90,in=180] (4,6) 
                    to[out=  0,in=120] (8,5) 
                    to[out=300,in=  0] (4,0);
 \end{tikzpicture}

 \end{document}

The second postaction draws a double line, but the gap between the two lines is not transparent. Therefore, I made the third postaction. But I expect that the tracks will look much more realistic (in particular at the switches) if the gap of the double lines is transparent. Any ideas?

Best Answer

This can be done (admittedly with some effort) using fadings and decorations. The following is I guess more proof-of-concept than anything else but might prove useful:

\documentclass[tikz, border=5]{standalone}
\usetikzlibrary{decorations,fit,fadings}

% Layers
\pgfdeclarelayer{sleeper}
\pgfdeclarelayer{rail}
\pgfsetlayers{sleeper,rail,main}

\pgfdeclaredecoration{tracks}{final}{%
\state{final}{%
  \pgftransformreset% <- I think is possibly vital.
  %
  % Get bounding box of decorated path as a node.
  % Must do it this way using basic layer.
  \pgftransformshift{\pgfpointanchor{current path bounding box}{south west}}%
  \pgfcoordinate{@1}\pgfpointorigin%
  \pgftransformshift{\pgfpointanchor{current path bounding box}{north east}}%
  \pgfcoordinate{@2}\pgfpointorigin%
  \node [fit=(@1)(@2), inner sep=\railsep+2*\railwidth] (@@) {};
  %
  % Create a fading for the track.
  \pgfinterruptpicture%
    \begin{tikzfadingfrompicture}[name=tracks]
    \path[draw=transparent!0, line width=\railsep+2*\railwidth, 
     postaction={draw=transparent!100, line width=\railsep}] 
      \pgfextra{\pgfsetpath\pgfdecoratedpath};
    \useasboundingbox (@@.south west) (@@.north east);
  \end{tikzfadingfrompicture}%
  \endpgfinterruptpicture
  %
  % Draw sleepers.
  \ifx\sleeperlayer\emptylayer\else\pgfonlayer{\sleeperlayer}\fi%
  \draw [draw=\sleepercolor,line width=\sleeperlength, dash pattern=on \sleeperwidth off \sleepersep, every sleeper/.try]
    \pgfextra{\pgfsetpath\pgfdecoratedpath};
  \ifx\sleeperlayer\emptylayer\else\endpgfonlayer\fi%
  %
  % Draw the track
  \ifx\raillayer\emptylayer\else\pgfonlayer{\raillayer}\fi%
  \fill [path fading=tracks, fit fading=false, 
    fading transform={shift=(@@.center)}, fill=\railcolor] 
   (@@.south west) rectangle (@@.north east);
   \ifx\raillayer\emptylayer\else\endpgfonlayer\fi%
}
}
\def\emptylayer{}
\tikzset{%
  track/.style={
    decoration=tracks, decorate
  },
  decorations/.cd,
    rail sep/.store in=\railsep,
    rail width/.store in=\railwidth,
    rail color/.store in=\railcolor,
    rail layer/.store in=\raillayer,
    sleeper sep/.store in=\sleepersep,
    sleeper width/.store in=\sleeperwidth,
    sleeper length/.store in=\sleeperlength,
    sleeper color/.store in=\sleepercolor,
    sleeper layer/.store in=\sleeperlayer,
    rail sep=4pt,
    rail width=1pt,
    rail color=black,
    rail layer=rail,
    sleeper sep=6pt,
    sleeper width=1pt,
    sleeper length=10pt,
    sleeper color=gray,
    sleeper layer=sleeper,
}
\begin{document}   
\begin{tikzpicture}
\draw [track] (-2,5) to (0,5) to[out=  0,in=270] (2,8);
\draw [track] (6,5) to (4,5) to[out=180,in=270] (2,8) to (2,10);
\end{tikzpicture}   
\end{document} 

enter image description here