25

a tube with water molecules inside

How can I generate the above image using TikZ. The oval inside tube represents water and arrows indicates the dipole orientation of water. What I was able to get so far is pasted below.

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
%%%<
\usepackage{verbatim}
\usepackage[active,tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\setlength\PreviewBorder{5pt}%
%%%>


\begin{document}
\tdplotsetmaincoords{30}{10}
\tikzset{every circle/.append style={x=1cm, y=1cm}}
\begin{tikzpicture}[tdplot_main_coords, rotate=90]

% --- Independent parameters ---
\pgfmathtruncatemacro\tA{3600}      % 10 turns 360 degree x 10=3600
\def\zA{1}                         % A begin point, define the length of cylinder 
\pgfmathtruncatemacro\tB{30}      % tB end of turn 
\def\zB{5}                         % B end point
\pgfmathtruncatemacro\NbPt{130}     % number of circles for drawing the helix portion 13 times 10 turns =130
\def\rhelixdots{0.14}              % radius of circles  forming helix

 % --- Draw helix ---
\pgfmathsetmacro\tone{\tA}
\pgfmathsetmacro\tlast{\tB}
\pgfmathsetmacro\ttwo{\tone+(\tlast-\tone)/(\NbPt-1)}
\pgfmathsetmacro\p{360*(\zB-\zA)/(\tB-\tA)}

\foreach \t in {\tone,\ttwo,...,\tlast}{%
\pgfmathtruncatemacro{\shadingcolor}{40*sin(\t+180)+80}
\shade[ball color=blue!\shadingcolor] ({0.7*cos(\t)},{0.7*sin(\t)},{\p*(\t-\tA)/360+\zA}) circle[radius=\rhelixdots];
\shade[ball color=red!\shadingcolor] ({0.7*cos(\t)},{0.7*sin(\t)},{\p*(\t-\tA)/360+\zA+0.2}) circle[radius=\rhelixdots];
}

\end{tikzpicture}
\end{document}

enter image description here

Looking for help, please have a look as well to this post Changing the view angle distort 3d tube image

Andrei
  • 525

1 Answers1

26

It is much easier to just draw everything in the correct order instead of using 3d coordinates (or layers).

The crucial part is the last dozen of lines:

\documentclass{standalone}
\usepackage{xifthen}
\usepackage{tikz}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}

\newdimen\r
\newdimen\R
\newcount\n

\tikzmath{
  \n = 19;                            % Molecules per winding
  \R = 100pt;                         % Tube radius
  \e = 0.9;                           % Eccentricity
  \t = 1.15;                          % Tightening factor
  \F = floor(\n/2);                   % Crucial to perform the clever cycles
  \G = \n-\F;                         %   (see the interesting part)
  \r = \R*sin(180/\n)*\t;             % 1/2 side of regular n-polygon, times t
}

% ##################################################### START OF BORING PART #

% These are the basic styles.
\tikzset{
  spirals/.cd,
    0/.style={draw, fill=white!70!black}, % {shade, ball color=white}
    1/.style={draw, fill=white!90!black}, % {shade, ball color=gray}
    8/.style={draw, fill=white!20!black}, % {shade, ball color=black}
    9/.style={opacity=0}
}

% Shaping the border. Boring.
\newcommand\ifisborderthen[4]{
  \ifthenelse{
        \(#2=0 \AND #3=0\)
    \OR \(#1=16 \AND #2<5\)
    \OR \(#1=3 \AND #2<1\)
    \OR \( #1=1  \AND \( #2<7 \OR \(#2<8 \AND #3=0\) \) \)
    \OR \( \(#1=17 \OR #1=2 \) \AND \(#2<5 \OR \(#2<6 \AND #3=0\)\) \)
    \OR \( \(#1=18 \OR #1=19\) \AND \(#2<6 \OR \(#2<7 \AND #3=0\)\) \)
  }{#4}{}}

% Shaping the hole. Boring.
\newcommand\ifisholethen[4]{
  \ifthenelse{
        \( #2<4 \AND \(2>#1 \OR #1>16\) \)
    \OR \(#1=1 \AND #2<5\)
    \OR \(#1=2 \AND #2<1 \AND #3=0\)
    \OR \(#1=19 \AND #2<6\)
    \OR \(#1=18 \AND #2<5\)
    \OR \(#1=17 \AND #2<5 \AND #3=0\)
  }{#4}{}}

% ################################################# START OF INTERESTING PART #

% We define a parametric key to apply the styles in a convenient way
\tikzset{
  molecule/.code args={#1in winding #2of spiral #3}{ % <-- HOCKETY POCKETY
    \tikzset{spirals/#3}                             % Draw everything.
    \ifisborderthen{#1}{#2}{#3}{\tikzset{spirals/8}} % Mark Borders.
    \ifisholethen{#1}{#2}{#3}{\tikzset{spirals/9}}}} % Punch holes.

\foreach \a [evaluate = \a using int(\a)]        % We cross (nearing viewer)
         in { \F, ..., 1                         %   first the lower side and
            , \F+1, \F+2, \F+..., \F+\G }        %   then the upper side
\foreach \z in {0, ..., 9}                       %     of ten windings
\foreach \h in {0, 1}                            %       of two spirals.
\path [molecule = \a in winding \z of spiral \h] % <--- HIGITUS FIGITUS
      ( {sqrt(1-\e^2)*\R*cos(-\a*360/\n)}        % This is the parametrization
      , {             \R*sin(-\a*360/\n)} )      %   of an ellipse.
        ++ ({\a*2*2*\r/\n}, 0)                   % We cut them open and
        ++ ({\z*2*2*\r}   , 0)                   % join them. Hence, spirals
        ++ ({\h*2*\r}     , 0)                   % that we intertwine.
        ++ (rand*360:rand*\r/20)                 % Some wobblyness.
      circle (\r);

\end{tikzpicture}
\end{document}

And this is the result:

Nice version

I didn't draw the thingies inside because I don't understand them. I didn't use faux-3d balls because I think they're horrible.

The depth fog effect (or the balls) are easy to add, and you already know how to do it. I focused on reproducing the given picture.


UPDATE!! It's 3D!

Horrible version

The new style is in the comments inside spirals.


UPDATE 2!! It's 3D-er!

Interestingly enough, the shading only eats the first coordinate. As an example, compare the previous figure (in which shading was computed using only the coordinate along the ellipse) with the following one that uses the full coordinate of the circles, except for the wobbliness correction:

\path [molecule = \a in winding \z of spiral \h] % <--- HIGITUS FIGITUS
      ( {sqrt(1-\e^2)*\R*cos(-\a*360/\n)         % Ellipses parametrized.
           + \a*2*2*\r/\n                        % We cut them open and
           + \z*2*2*\r                           % join them. Hence, spirals
           + \h*2*\r                    }        % that we intertwine.
      , {             \R*sin(-\a*360/\n)} )
        ++ (rand*360:rand*\r/20)                 % Some wobblyness.
      circle (\r);

Horriblest version

I didn't realize at first, but this allows for some tricks. As an example, consider this simple permutation:

\path [molecule = \a in winding \z of spiral \h]
           ({\a*2*2*\r/\n}, 0)
        ++ ({\z*2*2*\r}   , 0)
        ++ ({\h*2*\r}     , 0)
        ++ (rand*360:rand*\r/20)
        ++( {sqrt(1-\e^2)*\R*cos(-\a*360/\n)}
          , {             \R*sin(-\a*360/\n)} )
      circle (\r);

Cool version

That looks like a point light source inside the tube. Neat!