# Is there an efficient way to draw torus knots and related ''complicated lines'' (simple shapes, but on nontrivial surfaces) in TikZ?

In the process of typing up a set of lecture notes for a course, I found myself in need of a nice picture of a torus knot, which basically comes down to drawing a very complicated line. With some trickery, I was able to produce the simplest such knot, which is not even really a knot (but it's a start...). The code is as follows:

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}[scale=2]
\draw (-3.5,0) .. controls (-3.5,1.2) and (-1.5,1.5) .. (0,1.5);
\draw[xscale=-1] (-3.5,0) .. controls (-3.5,1.2) and (-1.5,1.5) .. (0,1.5);
\draw[rotate=180] (-3.5,0) .. controls (-3.5,1.2) and (-1.5,1.5) .. (0,1.5);
\draw[yscale=-1] (-3.5,0) .. controls (-3.5,1.2) and (-1.5,1.5) .. (0,1.5);

\draw (-2,.2) .. controls (-1.5,-0.05) and (-1,-0.15) ..
(0,-.15) .. controls (1,-0.15) and (1.5,-0.05) .. (2,0.2);
\draw (-1.7,0.1) .. controls (-1.5,0.15) and (-1,0.25) ..
(0,.25) .. controls (1,0.25) and (1.5,0.15) .. (1.7,0.1);
\begin{scope}[rotate=10]
\draw[draw=none] (0,-1.32) arc (270:630:3.06cm and 1.32cm)
coordinate[pos=0.375] (a) coordinate[pos=0.875] (b);
\draw[red] (0,-1.32) arc (270:405:3.06cm and 1.32cm);
\draw[red,densely dashed] (a) arc (45:225:3.06cm and 1.32cm);
\draw[red] (b) arc (225:270:3.06cm and 1.32cm);
\end{scope}
\end{tikzpicture}

\end{document}


and the output is: However, I'm also interested in being able to produce a picture of nontrivial knots such as a loop that wraps around one way three times while "going around the hole" once, and my method does not generalize. My question, therefore, is: Is it possible to efficiently produce pictures such as these (one may also think of natural generalizations like lines on surfaces of arbitrary genus), using TikZ? I should add that I already have a way of efficiently producing a picture of any (compact) orientable surface (without boundary, up to homotopy equivalence---I'm typing notes for an algebraic topology class): It's just the lines on them that I don't know how to quickly draw.

This is a related, yet much simpler question (not a duplicate).

• Maybe you could post the code for efficiently producing arbitrary orientatable surfaces? Generally, TikZ is not going to be the most efficient solution for 3D unless it is pretty simple, I don't think, because everything has to be faked i.e. it doesn't really think in 3D but only really knows about 2D. At least, that's how I understand it. – cfr Jan 19 '16 at 12:59
• @cfr The code for arbitrary orientable surfaces is just a slight modification from the torus: It replaces the right hand side of the torus by a segment that, when mirrored, can be "sewn" to the right hand side of a torus or, again, to itself. In principle I'm also open to usage of other packages, but I'd prefer a TikZ solution. – Danu Jan 19 '16 at 13:21
• (@cfr, and) In case there are math-haters, "arbitrary orientable surfaces" are well-classified and what Danu commented are all possibilities, up to homotopy equivalent. See this wiki section. That is to say, if one can draw what Danu commented, they can draw "all arbitrary orientable surfaces". Sounds exciting, right? – Symbol 1 Jan 19 '16 at 14:54
• @Symbol1 Yup, that's what I was talking about. I'll add the conditions compact & without boundary, I guess, to avoid confusion. – Danu Jan 19 '16 at 15:01
• – Chris Chudzicki Jan 20 '16 at 12:55

## 1 Answer

This approach checks if the normal vector is pointing to your eyes -- if so, it draws solid lines.

# Edit

Please compile this by XeLaTeX! Or one can replace greek letters in csnames by "safe" latin letters. \documentclass[border=9,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{decorations}

\begin{document}

\foreach\j in{10,20,...,360}{
\tdplotsetmaincoords{30}{\j}
\def\R{5}
\def\r{2}
\def\N{2}
\def\n{3}
\pgfmathsetmacro\S{30*\N*\n}
\pgfmathsetmacro\X{sin(-\tdplotmaintheta)*sin(-\tdplotmainphi)}
\pgfmathsetmacro\Y{sin(-\tdplotmaintheta)*cos(-\tdplotmainphi)}
\pgfmathsetmacro\Z{cos(-\tdplotmaintheta)}

\tikz[tdplot_main_coords]{
\path(-10cm,-10cm)(10cm,10cm);
\draw[dashed](\R+\r,0,0)foreach\i in{0,...,\S}{
\pgfextra{
\pgfmathsetmacro\t{360*\N*(\i/\S)}
\pgfmathsetmacro    \τ{\n/\N*\t}   \pgfmathsetmacro   \ι{\N*\t}
\pgfmathsetmacro\rsinτ{\r*sin(\τ)} \pgfmathsetmacro\sinι{sin(\ι)}
\pgfmathsetmacro\rcosτ{\r*cos(\τ)} \pgfmathsetmacro\cosι{cos(\ι)}
}
--({(\rcosτ+\R)*\cosι},{(\rcosτ+\R)*\sinι},\rsinτ)
};
\draw(\R+\r,0,0)foreach\i in{0,...,\S}{
\pgfextra{
\pgfmathsetmacro\t{360*\N*(\i/\S)}
\pgfmathsetmacro    \τ{\n/\N*\t}   \pgfmathsetmacro   \ι{\N*\t}
\pgfmathsetmacro\rsinτ{\r*sin(\τ)} \pgfmathsetmacro\sinι{sin(\ι)}
\pgfmathsetmacro\rcosτ{\r*cos(\τ)} \pgfmathsetmacro\cosι{cos(\ι)}
\pgfmathparse{
\rcosτ*\cosι*\X + \rcosτ*\sinι*\Y + \rsinτ*\Z
}
\ifdim\pgfmathresult pt<0pt
\def\to{--}
\else
\def\to{}
\fi
}
\to({(\rcosτ+\R)*\cosι},{(\rcosτ+\R)*\sinι},\rsinτ)
};
}
}
\end{document}


ascii version:

\documentclass[border=9,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{decorations}

\begin{document}

\foreach\j in{10,20,...,360}{
\tdplotsetmaincoords{30}{\j}
\def\R{5}
\def\r{2}
\def\N{2}
\def\n{3}
\pgfmathsetmacro\S{30*\N*\n}
\pgfmathsetmacro\X{sin(-\tdplotmaintheta)*sin(-\tdplotmainphi)}
\pgfmathsetmacro\Y{sin(-\tdplotmaintheta)*cos(-\tdplotmainphi)}
\pgfmathsetmacro\Z{cos(-\tdplotmaintheta)}

\tikz[tdplot_main_coords]{
\path(-10cm,-10cm)(10cm,10cm);
\draw[dashed](\R+\r,0,0)foreach\i in{0,...,\S}{
\pgfextra{
\pgfmathsetmacro\t{360*\N*(\i/\S)}
\pgfmathsetmacro    \TAU{\n/\N*\t}   \pgfmathsetmacro   \IOTA{\N*\t}
\pgfmathsetmacro\rsinTAU{\r*sin(\TAU)} \pgfmathsetmacro\sinIOTA{sin(\IOTA)}
\pgfmathsetmacro\rcosTAU{\r*cos(\TAU)} \pgfmathsetmacro\cosIOTA{cos(\IOTA)}
}
--({(\rcosTAU+\R)*\cosIOTA},{(\rcosTAU+\R)*\sinIOTA},\rsinTAU)
};
\draw(\R+\r,0,0)foreach\i in{0,...,\S}{
\pgfextra{
\pgfmathsetmacro\t{360*\N*(\i/\S)}
\pgfmathsetmacro    \TAU{\n/\N*\t}   \pgfmathsetmacro   \IOTA{\N*\t}
\pgfmathsetmacro\rsinTAU{\r*sin(\TAU)} \pgfmathsetmacro\sinIOTA{sin(\IOTA)}
\pgfmathsetmacro\rcosTAU{\r*cos(\TAU)} \pgfmathsetmacro\cosIOTA{cos(\IOTA)}
\pgfmathparse{
\rcosTAU*\cosIOTA*\X + \rcosTAU*\sinIOTA*\Y + \rsinTAU*\Z
}
\ifdim\pgfmathresult pt<0pt
\def\to{--}
\else
\def\to{}
\fi
}
\to({(\rcosTAU+\R)*\cosIOTA},{(\rcosTAU+\R)*\sinIOTA},\rsinTAU)
};
}
}

\end{document}