Helix on a cylinder

I want to plot geodesics on a cylinder. These are straight lines, circles or helices. I can plot the first two, but I don't know how to draw the helices.

To be precise, I would like to know how to draw an helix on this cylinder (passing thru two points A and B, but the location of the points is not relevant), using TikZ exclusively (maybe with pgfplots, but without using pstricks):

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\begin{document}
\begin{tikzpicture}
\node [cylinder,rotate=90,draw,aspect=2,minimum width=2cm,minimum height=3.5cm](C){};
\draw[fill] (-0.5,-0.5) circle [radius=0.045]node[below]{$A$};
\draw[fill] (0.5,0.75) circle [radius=0.045]node[below]{$B$};
\end{tikzpicture}
\end{document}

• Would this help? tex.stackexchange.com/a/73584/34618 – Jesse Aug 24 '13 at 9:21
• @Jesse I already tried that, but the plots of the cylinder and the helix (using \begin{axis} and \end{axis}) appear separated, instead of superimposed... – Grimolatto Aug 24 '13 at 9:25
• Use begin{tikzpicture}[overlay] and try. – Jesse Aug 24 '13 at 9:30
• OK. With the overlay option the plots superimpose, but with different scalings, and different origins. Note that the axis of my cylinder is the z axis. The addplot+3 figure seems to have its own system of coordinates. The cylinder has radius 1, so a parameterization of the helix with (cos(t),sin(t),t/5) should fit on it. But it does not... – Grimolatto Aug 24 '13 at 10:20
• I think the problem comes from the fact that the cylinder is actually a 2D object (drawn with straight lines and ellipses), and these 2D and 3D descriptions collide... – Grimolatto Aug 24 '13 at 10:27

I like @Gromolatto 's idea. However I believe that drawing hundreds of segments is an overkill. Here is his/her code using "\pgfplotfunction" which simplifies the code and increases precisicion since all points are ploted as they are without defining hunderes of sub-segments.

I left the original code in place and commented the lines that were replaced.

\documentclass{standalone}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usepackage{pgfplots}
\usetikzlibrary{shapes}
\tdplotsetmaincoords{60}{110}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\node [cylinder,rotate=90,draw,aspect=2,minimum width=2cm,minimum height=3.5cm](C){};

%\foreach \t in {-90,-75,...,0}{%
%  \draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
%}

\begin{scope}[color=black, dashed]
\pgfplothandlerlineto
\pgfplotfunction{\t}{-90,-89,...,15}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}

%  \foreach \t in {15,16,...,98}{%
%    \draw[line width=1.5pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.22+\t/360});
%  }

\begin{scope}[color=red]
\pgfplothandlerlineto
\pgfplotfunction{\t}{15,16,...,110}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}

%\foreach \t in {110,125,...,280}{%
%  \draw[line width=1pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.22+\t/360});
%}

\begin{scope}[color=red, dashed]
\pgfplothandlerlineto
\pgfplotfunction{\t}{110,111,...,303}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}

% \foreach \t in {303,304,...,340}{%
%   \draw[line width=1.6pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.19+\t/360});
% }

\begin{scope}[color=red]
\pgfplothandlerlineto
\pgfplotfunction{\t}{303,304,...,340}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}

%\foreach \t in {355,370}{%
%  \draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
%}

\begin{scope}[color=black, dashed]
\pgfplothandlerlineto
\pgfplotfunction{\t}{340,341,...,370}
{\pgfpointxyz {cos(\t)}{sin(\t)}{-0.25+\t/360}}
\pgfusepath{stroke}
\end{scope}

\def\ang{340}
\pgfmathsetmacro\bx{cos(\ang)}
\pgfmathsetmacro\by{sin(\ang)}
\pgfmathsetmacro\bz{-0.24+ \ang/360}

\coordinate (B) at (\bx,\by,\bz);

\draw[fill] (0.9922,0.25,-0.2) circle [x=1cm,y=1cm,radius=0.045]node[below]{$A$};
\draw[fill] (B) circle [x=1cm,y=1cm,radius=0.045]node[below]{$B$};
\end{tikzpicture}
\end{document}


Here is the figure obtained:

If you make a "zoom" you will see how this figure icreases precision.

• Wow! Excellent, it solves the resolution problems in my example. I think this version looks much better. – Grimolatto Nov 8 '15 at 17:41

Here is a tikz-3dplot solution. In case people are interested in drawing a more general helix (not just a geodesic) between two points of the cylinder, I've included a macro called \n to specify the number of additional turns around the cylinder.

Edit: thanks to Qrrbrbirlbel for his very helpful comment.

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{70}{15}
\tikzset{every circle/.append style={x=1cm, y=1cm}}
\begin{tikzpicture}[tdplot_main_coords]

% --- Independent parameters ---
\def\h{3}                          % cylinder height
\pgfmathtruncatemacro\tA{350}      % A angle
\def\zA{1}                         % A applicate
\pgfmathtruncatemacro\tB{150}      % B angle
\def\zB{2}                         % B applicate
\pgfmathtruncatemacro\n{0}         % number of additional turns
\pgfmathtruncatemacro\NbPt{51}     % number of dots for drawing the helix portion
\def\rhelixdots{0.02}              % radius of dots forming helix
\def\rAB{0.05}                     % radius of A and B dots

% --- Draw cylinder ---
% peripheral spokes
\foreach \t in {20,40,...,360}
{
\draw[gray,very thin,dashed] ({cos(\t)},{sin(\t)},0)
--({cos(\t)},{sin(\t)},\h);
}

% lower circle
\draw[black,very thin] (1,0,0)
\foreach \t in {2,3,...,360}
{
--({cos(\t)},{sin(\t)},0)
}
--cycle;

% upper circle
\draw[black,very thin] (1,0,\h)
\foreach \t in {2,4,...,360}
{
--({cos(\t)},{sin(\t)},\h)
}
--cycle;

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

% --- Draw A and B ---
\fill[blue] ({cos(\tA)},{sin(\tA)},\zA) circle [radius=\rAB]node[right]{$A$};
\fill[blue] ({cos(\tB)},{sin(\tB)},\zB) circle [radius=\rAB]node[left]{$B$};

\end{tikzpicture}
\end{document}

• I'm no expert in tikz-3dplot but without a unit the radius of the circles is taken in the x/y coordinate system of TikZ (which is changed by tikz-3dplot so that coordinates like (<x>, <y>, <z>) work as set up. Either use units (e.g. radius=3pt) or reset the coordinate system: circle[x=1cm, y=1cm, radius=\rAB]. A fix for all circles would be issuing \tikzset{every circle/.append style={x=1cm, y=1cm}}. – Qrrbrbirlbel Aug 24 '13 at 19:13
• I see what happens (incompatibility between coordinates)... The problem is that, as already said, I have drawn the other curves without problem, just with TikZ, and this approach forces me to redo everything, including the cylinder. I am surprised that such a simple thing requires such a sophisticated construction. But I'll give it a try!... – Grimolatto Aug 24 '13 at 20:23

Here is the solution exactly as I wanted it (it is based on the replies by Jubobs and Qrrbrbirlbel, but in a more simplified form). There are 5 different sectors depending on the color and the type of line (dashed or not). The points coordinates are computed so they lie on the helix:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{3dplot}
\usetikzlibrary{shapes.geometric}
\tdplotsetmaincoords{60}{110}
\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
\node [cylinder,rotate=90,draw,aspect=2,minimum width=2cm,minimum height=3.5cm](C){};
\foreach \t in {-90,-75,...,0}{%
\draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
}
\foreach \t in {15,16,...,98}{%
\draw[line width=1.5pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.22+\t/360});
}
\foreach \t in {110,125,...,280}{%
\draw[line width=1pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.22+\t/360});
}
\foreach \t in {303,304,...,340}{%
\draw[line width=1.6pt,color=red] ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+1)},{sin(\t +1)},{-0.19+\t/360});
}
\foreach \t in {355,370}{%
\draw ({cos(\t)},{sin(\t)},{-0.25+\t/360})--({cos(\t+7)},{sin(\t +7)},{-0.23+\t/360});
}
\draw[fill] (0.9922,0.25,-0.2) circle [x=1cm,y=1cm,radius=0.045]node[below]{$A$};
\draw[fill] (0.2739,-0.5,0.32) circle [x=1cm,y=1cm,radius=0.045]node[below]{$B$};
\end{tikzpicture}
\end{document}


There are some issues related to the density of lines near the turning points, but these can be easily adjusted by hand. When printed, this is OK:

• Well done. Best of luck on your future tikz adventures. – jub0bs Aug 27 '13 at 10:14

Here is a solution with pstricks in answer to a similar question:

\documentclass[x11names]{standalone}%
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\pagestyle{empty}
\usepackage{auto-pst-pdf}
\def\localbasis{\psline{<->}(1,0)(0,0)(0,1)}
\def\\M{6*\pstPI1}
\begin{document}

\footnotesize
\psset{xPlotpoints = 500, plotstyle=curve, linecolor = DarkSeaGreen3, algebraic, arrowinset=0.2, labelsep=3pt, dash=5pt 4pt}
\sffamily
\def\height {9.8}
\def\thetaend {0}
\def\thetaini {-305}
\def\sp{1.6}
\def\phase{0.7}
\psset{viewpoint=30 40 15 rtp2xyz, IIIDshowgrid = false}
\begin{pspicture}(-6,-2.5)(4,12)
\pnodes(-4,-0.08){L1}(-4, 8.23){L2}(-2.2,-0.08){C1}(-2.2,8.23){C2}(-3,-0.08){S1}(-3, 3.36){S2}(-2,3.36){C3}(0,-0.08){O}(2,-0.08){R}
\psset{linewidth=1.2pt, dimen=inner}
\parametricplotThreeD[arrows=c-](0, 3.10){%
\parametricplotThreeD[linecolor=DarkSeaGreen3!50!, linestyle=dashed](3.15,6.10){%
\parametricplotThreeD(6.18, 9.36){%68
\parametricplotThreeD[linecolor=DarkSeaGreen3!50!, linestyle=dashed](9.40, 12.35){%
\parametricplotThreeD[arrows=-c](12.45, 15.56){%
\psset{linewidth=0.5pt, linecolor=Coral1}
\ncline[offset=6pt]{<->}{L2}{L1}\ncput*{length}
\ncline{L1}{C1}\ncline{L2}{C2}
\ncline[offset=-6pt]{<->}{S1}{S2}\ncput*{spacing}
\ncline{S2}{C3}
\end{pspicture}

\end{document}


This is just to mention that the nice tricks of Fritz' great answer can be used here, too. The mathematics is even simpler for cylinders. This allows one to let pgfplots decide whether some stretch is on the front or in the back, and pgfplots also allows us to shade the thing as we want by just dialing an appropriate point meta.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\begin{document}
% very much like https://tex.stackexchange.com/a/199715/121799
\pgfplotsset{visible stretch/.style={restrict expr to
domain={sin(atan2(rawy,rawx)-\pgfkeysvalueof{/pgfplots/view/az})}{-1.1:0}},hidden
stretch/.style={restrict expr to
domain={sin(atan2(rawy,rawx)-\pgfkeysvalueof{/pgfplots/view/az})}{0:1.1}}}
}
\begin{tikzpicture}[declare function={R=1;H=3;}]
\begin{axis}[hide axis]
\pgfkeysvalueof{/pgfplots/view/az}:\pgfkeysvalueof{/pgfplots/view/az}-180,
colormap/blackwhite,point meta={sin(atan2(y,x)+40)}]
({R*cos(x)},
{R*sin(x)},{y});