# shading a bent tube

I want to build a tube-system. I have tried top, bottom, middle color with no success. How can I fill the bent tube?

\documentclass[tikz]{standalone}

\begin{document}

\tikzset{
pics/.cd,
% tubeh
tubeh/.style={
code={
\draw[top color=green, bottom color=green, middle color=white] (0,0)  rectangle +(2,1);
}%end code
}%end style
}%end tikzset
\tikzset{
pics/.cd,
% tubev
tubev/.style={
code={
\draw[left color=green, right color=green, middle color=white] (0,0)  rectangle +(1,2);
}%end code
}%end style
}%end tikzset
\tikzset{
pics/.cd,
% tubearc
tubearc/.style={
code={
% means 1cm in direction 0 degree
\draw[top color=green, bottom color=green, middle color=white] (0:1cm) -- (0:2cm)
% draw arc: start angle, end angle, radius
arc (0:90:2cm) -- (90:1cm)
arc (90:0:1cm) -- cycle;
}%end code
}%end style
}%end tikzset

\begin{tikzpicture}%
\draw[step=1, help lines](-2,-2) grid (5,2);
\foreach \x in {-2,...,5}
\draw (\x cm,1pt) -- (\x cm,-1pt) node[anchor=north] {$\x$};
\foreach \y in {-2,...,2}
\draw (1pt,\y cm) -- (-1pt,\y cm) node[anchor=east] {$\y$};

\path (-2,1)  pic {tubeh}
(0.0,0.0)  pic {tubearc}
(1,-2) pic {tubev};
\end{tikzpicture}

\end{document}

• Hello, and welcome, this site is English only. Bitte nur auf Englisch. – Alenanno Jan 8 '16 at 15:12
• If you prefer to post in German, there is texwelt.de/wissen. – Alan Munn Jan 8 '16 at 15:18
• @AlanMunn It was crossposted there. – Alenanno Jan 8 '16 at 15:19
• Normally, you cannot shade a curve. I suppose that with some hacking it would be possible, but that's beyond my knowledge. – Alenanno Jan 8 '16 at 15:25

This seems to be a largely unsolved problem within TeX.SE Questions and Answers.

• Percusse produced a usable solution
• Johannes asks a similar question but for shapes

A few questions that skirt the issue or are relevant to improve this answer are also present.

• This tackles shading, for example

Extending Percusse's code and wrapping it into a set of TikZ/PGF keys makes it useful to others. I have created to keys diffuse gradient and diffuse falloff which draw shaded lines by retracing the path multiple times.

\documentclass[tikz]{standalone}
\usepackage{graphicx}

\usetikzlibrary{positioning}

\tikzset{
diffuse color/.initial = black,                       % (1) The color value does not carry through to the pre- and post- actions
}

\tikzset{
linear opacity/.initial=0.5,                          %     Initial value must be defined here to define the next key
linear stroke/.style = {                              %     Define a style to draw a diffused sstroke
preaction={                                         %     This uses preactions to draw the gradiens
draw=\pgfkeysvalueof{/tikz/diffuse color},        %     Draw and colour the path (See 1). This is disabled by /tikz/diffuse gradient' (See 2)
line width = (2.0-#1)*\pgflinewidth,              %     Vary the Line width for each stroke, change 2.0 to 1.0 to normalize scaling
opacity=\pgfkeysvalueof{/tikz/linear opacity}}},  %     Keep resetting the opacity for each line, there is probably a cleaner means of setting this (See 3)
diffuse gradient/.style={                             %     This style executes /tikz/diffuse' stroke multiple times to achieve the gradient effect
draw = none,                                        % (2) Disable the default draw operation
linear opacity=#1,                                  % (3) Set a consistent value for opacity. In retrospect one could have simply assigned this to /tikz/opacity
linear stroke/.list={0.0,#1,...,1.0}},              %     Draw the line multiple times. Ideally we would use (1.0-1/#1) as the final value and (1/#1) as the stepsize
diffuse gradient/.default=1,                          %     Set an initial step size
}

\tikzset{
non-linear stroke/.style = {                          %     Define a style to draw a diffused sstroke
preaction={                                         %     This uses preactions to draw the gradiens
draw=\pgfkeysvalueof{/tikz/diffuse color},        %     Draw and colour the path (See 1). This is disabled by /tikz/diffuse falloff' (See 4)
line width = (2.0-#1)*\pgflinewidth,              %     Vary the Line width for each stroke, change 2.0 to 1.0 to normalize scaling
opacity=#1}},                                     %     Vary the opacity for each stroke
diffuse falloff/.style={                              %     This style executes /tikz/diffuse' stroke multiple times to achieve the gradient effect
draw = none,                                        % (4) Disable the default draw operation
non-linear stroke/.list={0.0,#1,...,1.0}},          %     Draw the line multiple times. Ideally we would use (1.0-1/#1) as the final value and (1/#1) as the stepsize
diffuse falloff/.default=1,                           %     Set an initial step size
}

\begin{document}

\begin{tikzpicture}
\draw [line width = 5pt, diffuse gradient= 0.5]                        (0, 3em) ++ (-1, -1) -- coordinate (A) ++ (1,1);
\draw [line width = 5pt, diffuse gradient=0.05]                        (0, 0em) ++ (-1, -1) -- coordinate (B) ++ (1,1);
\draw [line width = 5pt, diffuse gradient=0.25,postaction={draw, red}] (0,-3em) ++ (-1, -1) -- coordinate (C) ++ (1,1);
\node[right=of A] {Coarse Gradient};
\node[right=of B] {Fine Gradient};
\node[right=of C] {Enforced Line};
\end{tikzpicture}
\begin{tikzpicture}
\draw [line width = 5pt, diffuse falloff= 0.3]                        (0, 3em) ++ (-1, -1) -- coordinate (A) ++ (1,1);
\draw [line width = 5pt, diffuse falloff=0.05]                        (0, 0em) ++ (-1, -1) -- coordinate (B) ++ (1,1);
\draw [line width = 5pt, diffuse falloff=0.25,postaction={draw, red}] (0,-3em) ++ (-1, -1) -- coordinate (C) ++ (1,1);
\node[right=of A] {Coarse Gradient};
\node[right=of B] {Fine Gradient};
\node[right=of C] {Enforced Line};
\end{tikzpicture}

\end{document}


The code is well annotated so that one may follow what is going on (This is more for my own reference then anything else). The color assignment is a work around. Note that the colour comes out slighlty faded when using the diffuse gradient shader, I'm not entirely sure why this is. The coarse and fine gradient lines in the example output should both be black along the center, the latter is gray.

For the diffuse falloff the line is more sharply defined, this probably gives a better "tube". The original colour is also preserved.

The enforced line is really just for show and highlights differences in the shading strategies. The red indicates where the usual line might be drawn, this is really a bit construed as the multiplicative constant, 2.0, doubles the actual line width. This should be set to 1.0 if one uses the code, or convert this into a parameter, line spread.

The manner in which the shading is drawn allows for natural looking intersections as shown below

and of course an animation.

The ripples are done with the following :

\foreach \n in {0,0.025,...,1} {
\begin{tikzpicture}
\fill [inner color=blue!40!black, outer color=blue!60!black] circle (4em);
\begin{scope}
\path [clip] circle (4em);
\pgfmathsetmacro{\rA}{0.0 + mod(\n,1)}
\pgfmathsetmacro{\xA}{ 75 - 5*mod(\n,1)}
\draw [diffuse color = blue!\xA!black, line width = 2pt, diffuse falloff = 0.25] (0,0) circle (\rA em);
\pgfmathsetmacro{\rB}{1.0 + mod(\n,1)}
\pgfmathsetmacro{\xB}{ 70 - 5*mod(\n,1)}
\draw [diffuse color = blue!\xB!black, line width = 2pt, diffuse falloff = 0.25] (0,0) circle (\rB em);
\pgfmathsetmacro{\rC}{2.0 + mod(\n,1)}
\pgfmathsetmacro{\xC}{ 65 - 5*mod(\n,1)}
\draw [diffuse color = blue!\xC!black, line width = 2pt, diffuse falloff = 0.25] (0,0) circle (\rC em);
\pgfmathsetmacro{\rD}{3.0 + mod(\n,1)}
\pgfmathsetmacro{\xD}{ 60 - 5*mod(\n,1)}
\draw [diffuse color = blue!\xD!black, line width = 2pt, diffuse gradient= 0.25] (0,0) circle (\rD em);
\end{scope}
\end{tikzpicture}
}


## Update :

The tubes are drawn using the following code.

\begin{tikzpicture}[
detail/.style = {
preaction={draw, every diffuse, line width=2.1*\pgflinewidth, black},
preaction={draw, every diffuse, line width=2*\pgflinewidth, red},
diffuse color=red!50!blue,
rounded corners=0.75em,
},
square tube/.style={
line width = 0.25em,
every diffuse/.append style={line cap=rect},
detail
},
round tube/.style={
line width = 0.25em,
every diffuse/.append style={line cap=round},
detail
}
]
\draw[square tube] ( 0em, -1em) -| ( 2em, 1em) ( 3em,-1.5em) -- ( 3em,1em);
\draw[round tube]  ( 0em, -1em) -| (-2em, 1em) (-3em,-1.5em) -- (-3em,1em);
% \draw [thick, diffuse falloff= 0.3] (120:-120:1em);
\end{tikzpicture}


@cfr Everyone is a critic ;P

• This looks fantastic (+1), although not actually much like bent tubes ;). – cfr Jan 15 '17 at 2:57
• Hmm.. the only way I know of getting the lines across the ends of the tubes is to fiddle with the line caps. I've updated the answer to reflect this. It'd be nice if there was a tapered/chamferred line cap to intersect with vessels and containers. – Carel Jan 15 '17 at 3:31

You can (ab)use canvas transformations for that. They allow you to rotate shadings. All you need to do is to do is to patch rotated cones together.

\documentclass[tikz]{standalone}

\begin{document}

\tikzset{
pics/.cd,
% tubeh
tubeh/.style={
code={
\draw[top color=green, bottom color=green, middle color=white] (0,0)  rectangle +(2,1);
}%end code
}%end style
}%end tikzset
\tikzset{
pics/.cd,
% tubev
tubev/.style={
code={
\draw[left color=green, right color=green, middle color=white] (0,0)  rectangle +(1,2);
}%end code
}%end style
}%end tikzset
\tikzset{
pics/.cd,
% tubearc
tubearc/.style={
code={
% means 1cm in direction 0 degree
\draw[clip] (0:1cm) -- (0:2cm)
% draw arc: start angle, end angle, radius
arc (0:90:2cm) -- (90:1cm)
arc (90:0:1cm) -- cycle;
\foreach \X in {0,2,...,88} % <- the more steps, the more accurate
{\shade[left color=green, right color=green, middle
color=white,transform canvas={rotate=\X}]
(0:1cm) -- (0:2cm)
arc (0:{5}:2cm) -- ({5}:1cm)
arc ({5}:{0}:1cm) -- cycle;}
}%end code
}%end style
}%end tikzset

\begin{tikzpicture}%
\draw[step=1, help lines](-2,-2) grid (5,2);
\foreach \x in {-2,...,5}
\draw (\x cm,1pt) -- (\x cm,-1pt) node[anchor=north] {$\x$};
\foreach \y in {-2,...,2}
\draw (1pt,\y cm) -- (-1pt,\y cm) node[anchor=east] {$\y$};

\path (-2,1)  pic {tubeh}
(0.0,0.0)  pic {tubearc}
(1,-2) pic {tubev};
\end{tikzpicture}

\end{document}

\documentclass[tikz]{standalone}

\begin{document}

\tikzset{
pics/.cd,
% tubeh
tubeh/.style={
code={
\draw[top color=green, bottom color=green, middle color=white] (0,0)  rectangle +(2,1);
}%end code
}%end style
}%end tikzset
\tikzset{
pics/.cd,
% tubev
tubev/.style={
code={
\draw[left color=green, right color=green, middle color=white] (0,0)  rectangle +(1,2);
}%end code
}%end style
}%end tikzset
\tikzset{
pics/.cd,
% tubearc
tubearc/.style={
code={
% means 1cm in direction 0 degree
\draw[top color=green, bottom color=green, middle color=white] (0:1cm) -- (0:2cm)
% draw arc: start angle, end angle, radius
arc (0:90:2cm) -- (90:1cm)
arc (90:0:1cm) -- cycle;
}%end code
}%end style
}%end tikzset

\begin{tikzpicture}%
\draw[step=1, help lines](-2,-2) grid (5,2);
\foreach \x in {-2,...,5}
\draw (\x cm,1pt) -- (\x cm,-1pt) node[anchor=north] {$\x$};
\foreach \y in {-2,...,2}
\draw (1pt,\y cm) -- (-1pt,\y cm) node[anchor=east] {$\y$};

\path (-2,1)  pic {tubeh}
(0.0,0.0)  pic {tubearc}
(1,-2) pic {tubev};
\end{tikzpicture}

\end{document}