4

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}
8
  • 1
    Hello, and welcome, this site is English only. Bitte nur auf Englisch.
    – Alenanno
    Commented Jan 8, 2016 at 15:12
  • If you prefer to post in German, there is texwelt.de/wissen.
    – Alan Munn
    Commented Jan 8, 2016 at 15:18
  • @AlanMunn It was crossposted there.
    – Alenanno
    Commented Jan 8, 2016 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
    Commented Jan 8, 2016 at 15:25
  • texwelt.de/wissen/fragen/15725/…
    – Johannes_B
    Commented Jan 9, 2016 at 1:10

2 Answers 2

6

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.

Radial linear gradient with constant opacity

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

Radial non-linear gradient with varying opacity

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

Intersection of graduated lines

and of course an animation.

Ripples in a circular pond, or something to that effect

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, 
  diffuse gradient=0.06,
  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}

*Bloody* Bent Tubes ;P

@cfr Everyone is a critic ;P

2
  • This looks fantastic (+1), although not actually much like bent tubes ;).
    – cfr
    Commented Jan 15, 2017 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
    Commented Jan 15, 2017 at 3:31
3

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}

enter image description here

You must log in to answer this question.

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