# 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 Aug 24, 2013 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... Aug 24, 2013 at 9:25
• Use begin{tikzpicture}[overlay] and try. Aug 24, 2013 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... Aug 24, 2013 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... Aug 24, 2013 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. Nov 8, 2015 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}}. Aug 24, 2013 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!... Aug 24, 2013 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. Aug 27, 2013 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});