4

I have to implement an array made up of cylindrical like elements. However, below code can only provide a straight cylinder (code credit goes to this link), instead I need to bend it like in the figure shown, may not be at that angle but vertical. But I couldn't seem to succeed. I couldn't even seem to increase the number of cylinder from one to more.

\documentclass[border=2mm]{standalone}
\usepackage{xcolor}
\definecolor{mycolor}{RGB}{8,108,131}
\usepackage{tikz} 
\usetikzlibrary{positioning}
\usetikzlibrary{backgrounds}
\usetikzlibrary{shapes.geometric}
\usetikzlibrary{calc}
\tikzset{cylinder end fill/.style={path picture={
            \pgftransformshift{\centerpoint}%
            \pgftransformrotate{\rotate}%  
            \pgfpathmoveto{\beforetop}%
            \pgfpatharc{90}{-270}{\xradius and \yradius}%
            \pgfpathclose
            \pgfsetfillcolor{#1}%
            \pgfusepath{fill}}
}}
\begin{document}
    \begin{tikzpicture}
    \begin{scope}[on background layer]
    \path let \p1=(0.2,8.4),
    \n1={atan2(\y1,\x1)},\n2={veclen(\y1,\x1)} in
    node[cylinder, rotate=270,
    minimum height=0.85*\n2,minimum width=1cm,aspect=1.0,
    cylinder end fill=red,
    left color=red!30,right color=black,middle color=red!80, opacity=0.7,
    draw] at (0.8,4.7) {1};
    \end{scope}
    \end{tikzpicture}
\end{document} 

enter image description here

Shamina
  • 1,078
  • I am not sure if TikZ is the best tool to do this if you want all the lighting as in the screen shot. With asymptote you can draw nice pipes, see e.g. https://tex.stackexchange.com/a/404274. –  Mar 19 '20 at 23:03
  • If you do not want the lighting (nor the perspective view) it is trivial to draw this. –  Mar 19 '20 at 23:09
  • @Schrödinger'scat I actually need perspective. But I couldn't get the lightning part? You mean the grayish coloring? – Shamina Mar 19 '20 at 23:12
  • Yes. The fact that the color is not uniform. It is nontrivial to get this with TikZ, in particular if it is supposed to look semi-realistic. –  Mar 19 '20 at 23:16
  • @Schrödinger'scat Aah I see, I don't need such a shade. It is not really important for me, only perspective, I would say. – Shamina Mar 19 '20 at 23:21
  • I love the design... is it a bus from an electrical circuit? :-) – Sebastiano Mar 19 '20 at 23:55
  • 1
    @Sebastiano It is an optical waveguide in a silica medium. – Shamina Mar 20 '20 at 14:21
  • @Shamina It is very nice your drawing instead of Schrödinger's cat :-) – Sebastiano Mar 20 '20 at 20:10

1 Answers1

7

Here is an answer which produces something long these lines. The key ingredient is the perspective library. It utilizes a nice trick by Symbol 1 (and, as usual, the really cool things do not have much votes... ;-) which allows us to avoid to write tpp cs:x=...,y=...,z=..., we can just coordinates and the switch switch on perspective. Since decorations cause dimension too large errors, the color gradient and change of line width is achieved through loops, which is why this takes some time to compile (12s on a 5 year old MacBook Pro). A faster, decoration-based answer that works for not too curvy paths can be found below.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{calc,perspective,3d}
\makeatletter
\tikzset{switch on perspective/.code={\def\tikz@parse@splitxyz##1##2##3,##4,{%
    \def\pgfutil@next{\tikz@scan@one@point##1(tpp cs:x={##2},y={##3},z={##4})}% https://tex.stackexchange.com/a/365418/194703
}}}
\makeatother

\begin{document}
\begin{tikzpicture}[3d view={-70}{15}]
 \begin{scope}[perspective={p = {(20,0,0)}, q = {(0,20,0)}},switch on perspective]
  \path let \p1=($(0,2,0)-(0,0,0)$),\p2=($(20,2,0)-(20,0,0)$),
     \n1={atan2(\y1,\x1)/2+atan2(\y2,\x2)/2} in
   [left color=black,right color=gray!80!black,shading angle=\n1]
    (0,-3,0) -- (0,3,0) -- (20,3,0) -- (20,-3,0) -- cycle;
  \begin{scope}
   \clip (1,-3,0) -- (1,3,0) -- (20,3,0) -- (20,-3,0) -- cycle;
   \foreach \X [count=\Y] in {2,1.2,-1.2,-2}
   {\foreach \Z [evaluate=\Z as \CF using {int(90-\Z/3)}] in {1,...,95}
   {\draw let 
    \p1=($(0.8+\Z/5,\X+0.5,0)-(0.8+\Z/5,\X-0.5,0)$),
    \n1={sqrt(\x1*\x1+\y1*\y1)} in [line width=0.1*\n1,gray!\CF!black]
    plot[variable=\t,domain=0.8+\Z/5:0.8+\Z/5+0.4,samples=5,smooth] 
    (\t,{\X+0.2*pow(-1,\Y+1)*isodd(int(\t/2.05))},0) ;}}
  \path foreach \X [count=\Y] in {2,1.2,-1.2,-2}
   {(1,{\X+pow(-1,\Y+1)*0.2*isodd(int(1/2.05))},0) coordinate (aux\Y) };        
  \end{scope}   
 \end{scope}
 \begin{scope}[canvas is xz plane at y=0]
  \fill[rotate=-15] foreach \X in {1,...,4} {(aux\X) circle[x radius=5pt,y radius=1pt]};
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

For straight cylinders there is no problem, the decoration is well-behaved.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{calc,decorations,perspective,3d}
\makeatletter
\tikzset{switch on perspective/.code={\def\tikz@parse@splitxyz##1##2##3,##4,{%
    \def\pgfutil@next{\tikz@scan@one@point##1(tpp cs:x={##2},y={##3},z={##4})}% https://tex.stackexchange.com/a/365418/194703
}}}
\makeatother
% the following decoration is based on
% https://tex.stackexchange.com/a/14295/128068 and
% https://tex.stackexchange.com/a/471222
\pgfkeys{/pgf/decoration/.cd,
         start color/.store in=\startcolor,
         start color=black,
         end color/.store in=\endcolor,
         end color=black,
         varying line width steps/.initial=100
}
\pgfdeclaredecoration{width and color change}{initial}{
 \state{initial}[width=0pt, next state=line, persistent precomputation={%
   \pgfmathparse{\pgfdecoratedpathlength/\pgfkeysvalueof{/pgf/decoration/varying line width steps}}%
   \let\increment=\pgfmathresult%
   \def\x{0}%
 }]{}
 \state{line}[width=\increment pt,   persistent postcomputation={%
   \pgfmathsetmacro{\x}{\x+\increment}
   },next state=line]{%
   \pgfmathparse{varyinglw(100*(\x/\pgfdecoratedpathlength))}
   \pgfsetlinewidth{\pgfmathresult pt}%
   \pgfpathmoveto{\pgfpointorigin}%
   \pgfmathsetmacro{\steplength}{1.4*\increment}
   \pgfpathlineto{\pgfqpoint{\steplength pt}{0pt}}%
   \pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
   \pgfsetstrokecolor{\endcolor!\y!\startcolor}%
   \pgfusepath{stroke}%
 }
 \state{final}{%
   \pgfsetlinewidth{\pgflinewidth}%
   \pgfpathmoveto{\pgfpointorigin}%
   \pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
   \color{\endcolor!\y!\startcolor}%
   \pgfusepath{stroke}% 
 }
}


\begin{document}
\begin{tikzpicture}[3d view={-70}{15}]
 \begin{scope}[perspective={p = {(20,0,0)}, q = {(0,20,0)}},switch on perspective]
  \path let \p1=($(0,2,0)-(0,0,0)$),\p2=($(20,2,0)-(20,0,0)$),
     \n1={atan2(\y1,\x1)/2+atan2(\y2,\x2)/2} in
   [left color=black,right color=gray!80!black,shading angle=\n1]
    (0,-3,0) -- (0,3,0) -- (20,3,0) -- (20,-3,0) -- cycle;
  \begin{scope}
   \clip (1,-3,0) -- (1,3,0) -- (20,3,0) -- (20,-3,0) -- cycle;
   \foreach \X [count=\Y] in {2,1.2,-1.2,-2}
   {\draw[decorate,decoration={width and color change}] let 
    \p1=($(10,\X+0.5,0)-(10,\X-0.5,0)$),\p2=($(1,\X+0.5,0)-(1,\X-0.5,0)$),
    \n1={sqrt(\x1*\x1+\y1*\y1)},\n2={sqrt(\x2*\x2+\y2*\y2)} in
    [declare function={varyinglw(\x)=0.1*\n1+0.1*(\n2-\n1)*\x/100;},
    /pgf/decoration/start color=gray!70!black,/pgf/decoration/end color=gray]
   (20,\X,0) -- (1,\X,0) coordinate (aux\Y);}
  \end{scope}   
 \end{scope}
 \begin{scope}[canvas is xz plane at y=0]
  \fill[rotate=-15] foreach \X in {1,...,4} {(aux\X) circle[x radius=5pt,y radius=1pt]};
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Probably one can find parameter regions in which the curved paths work, too, but it might be a better investment of time to try to teach these decorations fpu.

  • It is a great answer!! Thanks a lot for investing so much time in it!!! I seriously need this answer as well but my given screenshot was just an imitation to be done from the code I provided. If my code is run, it gives a cylinder but can that cylinder be made sinusoidal was actually my question. I badly present it, however, this was actually my second part. Many thanks again! – Shamina Mar 20 '20 at 09:46
  • I am sorry to wake you up again for this. But this beautiful answer is helping me a lot. However, I was unable to remove the angle the picture has with vertical axis. To be more precise, the cylindrical pipes are at some angle with the vertical axis, is there a way to remove this angle make them completely vertical (or straight)? Many thanks :) – Shamina May 04 '20 at 10:35
  • @Shamina Straight with a perspective view or just straight (from the top of the screen to the bottom)? –  May 04 '20 at 14:14
  • Without perspective would do thee job. Exactly from the top of the screen to the bottom! – Shamina May 04 '20 at 14:21
  • @Shamina In the second code replace \begin{tikzpicture}[3d view={-70}{15}] \begin{scope}[perspective={p = {(20,0,0)}, q = {(0,20,0)}},switch on perspective] by \begin{tikzpicture} \begin{scope}[rotate=90], and remove \fill[rotate=-15] foreach \X in {1,...,4} {(aux\X) circle[x radius=5pt,y radius=1pt]};. –  May 04 '20 at 14:29
  • Thanks a lot!! Possibly last trouble, if I need the perspective on top of this? – Shamina May 04 '20 at 14:33
  • @Shamina I think these statements are somewhat contradicting. You can use \begin{tikzpicture}[rotate=90,3d view={0}{90}] \begin{scope}[switch on perspective] and also remove the circles in the end. Now you can add some values of perspective={p = {(20,0,0)}, q = {(0,20,0)}} where you have to play with the entries of p and q until you are happy and get the perspective you want. –  May 04 '20 at 14:39
  • That solves my problem, many thanks to you. I guess the cylidrical pipes can still be made more darker? I mean more contrasting from the background color – Shamina May 04 '20 at 14:48
  • @Shamina The colors are all stored in /pgf/decoration/start color=gray!70!black,/pgf/decoration/end color=gray, you can choose whatever color you like. –  May 04 '20 at 14:49