Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am trying to draw the following image with TIKZ. My question is that, is it possible to bend 3D objects in TIKZ. I would like to bend the cylinder object in the code that I have given below and produce the following figure.

enter image description here

What I have achieved so far is to draw a cylinder with tikz -

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\radius}{0.25}
\pgfmathsetmacro{\length}{5}

\fill[fill=white] (\radius,0) -- (\radius,\length) arc (360:180:\radius cm and 0.5*\radius cm) -- (-\radius,0) arc (180:360:\radius cm and \radius cm);
\fill[top color=gray!90!,bottom color=gray!2,middle color=gray!30,shading=axis,opacity=0.25] (0,\length) circle (\radius cm and 0.5*\radius cm);
\draw[ultra thick,gray!90] (-\radius,\length) -- (-\radius,0) arc (180:360:\radius cm and \radius cm) -- (\radius,\length) ++ (-\radius,0) circle (\radius cm and 0.5*\radius cm);
\end{tikzpicture} 
\end{document} 

Thank You !

share|improve this question

1 Answer 1

up vote 19 down vote accepted

Here is an idea you can use as starting point.

The approach is to generate random angles at the tips of the cylinder, and random "strenght" (I was unable to make up a better term), and use these amounts to place the control points of a bezier curve, in relative polar coordinates with respect those tips. The same angle and strength is used for both edges of the cylinder, to ensure that they keep parallel.

In order to draw these kind of cylinders in different places, angles and scales, all the code is stored in a pic (PGF 3.0.0 is required).

There is still room for improvements, in particular, I think that parameters such as the cylinder length and radius should be given as keys for the pic, as well as the "randomness" of the angle and strength of the deformation.

Code for the pic style:

\pgfmathsetmacro{\radius}{0.25}
\pgfmathsetmacro{\length}{5}

\tikzset {
    bent cylinder/.pic={
        \pgfmathsetmacro{\anglebottom}{90-20+40*rnd}
        \pgfmathsetmacro{\strengthbottom}{\length*(0.3+rnd/3)}
        \pgfmathsetmacro{\angletop}{90-20+40*rnd}
        \pgfmathsetmacro{\strengthtop}{\length*(0.3+rnd/3)}

        \fill[fill=white] 
              (\radius,0) 
           .. controls +(\anglebottom:\strengthbottom) 
                   and +(-\angletop:\strengthtop) 
           .. (\radius,\length) 
              arc (360:180:\radius cm and 0.5*\radius cm) 
           .. controls +(-\angletop:\strengthtop) 
                   and +(\anglebottom:\strengthbottom) 
           .. (-\radius,0) 
              arc (180:360:\radius cm and \radius cm);
        \draw[gray!90, ultra thick, line join=round]
              (\radius,0) 
           .. controls +(\anglebottom:\strengthbottom) 
                   and +(-\angletop:\strengthtop) 
           .. (\radius,\length) 
              arc (360:180:\radius cm and 0.5*\radius cm) 
           .. controls +(-\angletop:\strengthtop) 
                   and +(\anglebottom:\strengthbottom) 
           .. (-\radius,0) 
              arc (180:360:\radius cm and \radius cm);
        \filldraw[ultra thick, draw=gray!90,
                  top color=gray!90,
                  bottom color=gray!2,
                  middle color=gray!30,
                  shading=axis]
            (0,\length) circle (\radius cm and 0.5*\radius cm);
   }
}

Examples of use

A "sequence" of vertical cylinders, to see how each one is bent in different shape and amount:

\begin{tikzpicture}
    \fill[left color=black!40, right color=white] (0,-2) rectangle (16,7);
    \foreach \x in {1,...,10}
    \draw (2*\x,0) pic {bent cylinder};
\end{tikzpicture}

Result

A "spaghetti mess", similar to the figure you posted. Each cylinder is placed at a random location and rotated a random angle:

\begin{tikzpicture}
    \fill[left color=black!40, right color=white] (0,-2) rectangle (15,7);
    \foreach \x in {1,...,60}
    \draw (10*rnd,4*rnd) pic[rotate=360*rnd] {bent cylinder};
\end{tikzpicture} 

Mess

Update

A better placement of the tubes in the "mess" can be achieved via poisson sampling. Using the lua library I provided in another answer, the centers of the cylinders can be placed in a random lattice which ensures a minimum distance between them.

In the following code I changed the definition of the bent cylinder pic to put the point (0,0) at the center of the cylinder (instead of its base), and to remove some unnecesary code. I used \poissonpointslist{15}{7}{1}{20} to place random coordinates in a rectangle of 15x7, and ensuring a minimum distance of 1 among points (the parameter 20 is irrelevant here), and a \foreach loop which uses these coordinates to put a cylinder at that point, randomly rotated around it.

For better understanding of the result, I placed an orange background in the 15x7 rectangle containing the centers of the cylinders, and a yellow circle at each of those centers.

\documentclass{standalone}
\usepackage{tikz}
\usepackage{poisson}
\begin{document}
\pgfmathsetmacro{\radius}{0.25}
\pgfmathsetmacro{\length}{5}

\tikzset {
    bent cylinder/.pic={
        \pgfmathsetmacro{\anglebottom}{90-20+40*rnd}
        \pgfmathsetmacro{\strengthbottom}{\length*(0.3+rnd/3)}
        \pgfmathsetmacro{\angletop}{90-20+40*rnd}
        \pgfmathsetmacro{\strengthtop}{\length*(0.3+rnd/3)}


        \filldraw[fill=white, draw=gray!90, ultra thick, line join=round] 
              (\radius,-\length/2) 
           .. controls +(\anglebottom:\strengthbottom) 
                   and +(-\angletop:\strengthtop) 
           .. (\radius,\length/2) 
              arc (360:180:\radius cm and 0.5*\radius cm) 
           .. controls +(-\angletop:\strengthtop) 
                   and +(\anglebottom:\strengthbottom) 
           .. (-\radius,-\length/2) 
              arc (180:360:\radius cm and \radius cm);
        \filldraw[ultra thick, draw=gray!90,
                  top color=gray!90,
                  bottom color=gray!2,
                  middle color=gray!30,
                  shading=axis]
            (0,\length/2) circle (\radius cm and 0.5*\radius cm);
   }
}

\edef\positions{\poissonpointslist{15}{7}{1}{20}}

\begin{tikzpicture}
    \fill[black!30]  (-2.5,-2.5) rectangle (17.5,9.5);
    \fill[orange!20] (0,0) rectangle (15,7);
    \foreach \x/\y in \positions
        \draw (\x,\y) pic[rotate=360*rnd] {bent cylinder};
    \foreach \x/\y in \positions 
        \fill[yellow!50!orange, opacity=0.7] (\x,\y) circle(0.3);
\end{tikzpicture} 
\end{document} 

Result

share|improve this answer
1  
this is great ! –  Raj Jun 18 at 15:23
    
your updated answer looks much better than the previous one. –  Raj Jun 19 at 13:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.