# Drawing Torus with semi-dashed line on it [duplicate]

I would like to draw :

To draw the above torus, I have used the following codes :

\documentclass[margin=2mm,tikz]{standalone}
\usepackage{pgfplots}
\begin{document}
%Oberflächenproblem
\begin{tikzpicture}[rotate=180]
%Torus
\draw (0,0) ellipse (1.6 and .9);
%Hole
\begin{scope}[scale=.8]
\path[rounded corners=24pt] (-.9,0)--(0,.6)--(.9,0) (-.9,0)--(0,-.56)--(.9,0);
\draw[rounded corners=28pt] (-1.1,.1)--(0,-.6)--(1.1,.1);
\draw[rounded corners=24pt] (-.9,0)--(0,.6)--(.9,0);
\end{scope}
%Cut 1
\draw[densely dashed] (0,-.9) arc (270:90:.2 and .365);
\draw (0,-.9) arc (-90:90:.2 and .365);
%Cut 2
\draw (0,.9) arc (90:270:.2 and .348);
\draw[densely dashed] (0,.9) arc (90:-90:.2 and .348);
\end{tikzpicture}
\end{document}


It produces:

This is not the same what I want. How can I do the desired torus?

• I have no idea about asymptote. If the figure is possible with an asymptote, then I have no problem@ marmot. – MKS Mar 9 '19 at 2:55
• This site is full of examples using asymptote for that. I did a quick search, and for instance tex.stackexchange.com/a/135438/121799 looks already rather close to what you want. If you do a google image search for site:tex.stackexchange.com asymptote torus you will find many more examples. – user121799 Mar 9 '19 at 3:16
• Given the number of different questions and answers here relating to drawing tori, I think this question would benefit from a bit of clarity as to what aspects of your picture you regard as crucial and which aren't important. For example, is the shading important? Is the position of the ellipses important? What, exactly, is wrong with what you've produced to date? – Andrew Stacey Mar 9 '19 at 9:52
• Why is "your" code so similar to tex.stackexchange.com/a/155724/121799 ? – user121799 Mar 9 '19 at 23:09

The question of how to draw a torus with TikZ is a rather old one and has several excellent answers. And the most spectacular outputs have (IMHO) been achieved with asymptote, which has, unlike TikZ, a 3d engine. However, it turns out that if one aims at 3d vector graphics, the efforts required drawing 3d tori are more substantial than one may naively expect.

This raises the question of whether or not it is possible to make TikZ discriminate between visible and "hidden" points on the torus surface. After all, the analogous discrimination has been achieved for spheres. The answer is yes.

Part I of the answer: how can one draw the contour of a torus? Given a parametization of the torus, T(\u,\v)=(cos(\u)*(\R + \r*cos(\v),(\R + \r*cos(\v))*sin(\u),\r*sin(\v)), one can compute the tangents and then the normal at a given point. The boundary of the torus is determined by the requirement that the normal be orthogonal to the normal of the screen. The resulting curve is then a function T(\u,vcrit(\u)). The critical \v values have a very simple representation:

vcrit1(\u,\th)=atan(tan(\th)*sin(\u));% first critical v value
vcrit2(\u,\th)=180+atan(tan(\th)*sin(\u));% second critical v value


They determine where the visible and/or hidden pieces of cycles wrapping the torus start or end. Note, however, that the contour vcrit2 may, depending on the view angle \tdplotmaintheta, have self-interactions. This is why there is a discriminant in the below code.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{70}{0}
\tikzset{declare function={torusx(\u,\v,\R,\r)=cos(\u)*(\R + \r*cos(\v));
torusy(\u,\v,\R,\r)=(\R + \r*cos(\v))*sin(\u);
torusz(\u,\v,\R,\r)=\r*sin(\v);
vcrit1(\u,\th)=atan(tan(\th)*sin(\u));% first critical v value
vcrit2(\u,\th)=180+atan(tan(\th)*sin(\u));% second critical v value
disc(\th,\R,\r)=((pow(\r,2)-pow(\R,2))*pow(cot(\th),2)+%
pow(\r,2)*(2+pow(tan(\th),2)))/pow(\R,2);% discriminant
umax(\th,\R,\r)=ifthenelse(disc(\th,\R,\r)>0,asin(sqrt(abs(disc(\th,\R,\r)))),0);
}}

\begin{tikzpicture}[tdplot_main_coords]
\pgfmathsetmacro{\R}{4}
\pgfmathsetmacro{\r}{1}
\draw[thick,fill=gray,even odd rule,fill opacity=0.2] plot[variable=\x,domain=0:360,smooth,samples=71]
({torusx(\x,vcrit1(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit1(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit1(\x,\tdplotmaintheta),\R,\r)})
plot[variable=\x,
domain={-180+umax(\tdplotmaintheta,\R,\r)}:{-umax(\tdplotmaintheta,\R,\r)},smooth,samples=51]
({torusx(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)})
plot[variable=\x,
domain={umax(\tdplotmaintheta,\R,\r)}:{180-umax(\tdplotmaintheta,\R,\r)},smooth,samples=51]
({torusx(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)});
\draw[thick] plot[variable=\x,
domain={-180+umax(\tdplotmaintheta,\R,\r)/2}:{-umax(\tdplotmaintheta,\R,\r)/2},smooth,samples=51]
({torusx(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)});
\foreach \X  in {240,300}
{\draw[thick,dashed]
plot[smooth,variable=\x,domain={360+vcrit1(\X,\tdplotmaintheta)}:{vcrit2(\X,\tdplotmaintheta)},samples=71]
({torusx(\X,\x,\R,\r)},{torusy(\X,\x,\R,\r)},{torusz(\X,\x,\R,\r)});
\draw[thick]
plot[smooth,variable=\x,domain={vcrit2(\X,\tdplotmaintheta)}:{vcrit1(\X,\tdplotmaintheta)},samples=71]
({torusx(\X,\x,\R,\r)},{torusy(\X,\x,\R,\r)},{torusz(\X,\x,\R,\r)})
node[below]{$C\ifnum\X=300 '\fi$};
}
\draw[thick] plot[smooth,variable=\x,domain=60:420,samples=71]
({torusx(-15+15*cos(\x),80+45*sin(\x),\R,\r)},
{torusy(-15+15*cos(\x),80+45*sin(\x),\R,\r)},
{torusz(-15+15*cos(\x),80+45*sin(\x),\R,\r)})
node[above left]{$C''$};
\end{tikzpicture}
\end{document}


As you can see, the visible (solid) or hidden (dashed) contours run between vcrit1 and vcrit2, which are functions of \u and the view angle.

One can then vary the positions of the cycle(s) and the view angle.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\begin{document}
\foreach \X in {0,10,...,350}
{\tdplotsetmaincoords{65+10*sin(\X)}{0}
\tikzset{declare function={torusx(\u,\v,\R,\r)=cos(\u)*(\R + \r*cos(\v));
torusy(\u,\v,\R,\r)=(\R + \r*cos(\v))*sin(\u);
torusz(\u,\v,\R,\r)=\r*sin(\v);
vcrit1(\u,\th)=atan(tan(\th)*sin(\u));% first critical v value
vcrit2(\u,\th)=180+atan(tan(\th)*sin(\u));% second critical v value
disc(\th,\R,\r)=((pow(\r,2)-pow(\R,2))*pow(cot(\th),2)+%
pow(\r,2)*(2+pow(tan(\th),2)))/pow(\R,2);% discriminant
umax(\th,\R,\r)=ifthenelse(disc(\th,\R,\r)>0,asin(sqrt(abs(disc(\th,\R,\r)))),0);
}}

\begin{tikzpicture}[tdplot_main_coords]
\pgfmathsetmacro{\R}{4}
\pgfmathsetmacro{\r}{1}
\path[tdplot_screen_coords,use as bounding box]
(-1.3*\R,-1.3*\R) rectangle (1.3*\R,1.3*\R);
\draw[thick,fill=gray,even odd rule,fill opacity=0.2] plot[variable=\x,domain=0:360,smooth,samples=71]
({torusx(\x,vcrit1(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit1(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit1(\x,\tdplotmaintheta),\R,\r)})
plot[variable=\x,
domain={-180+umax(\tdplotmaintheta,\R,\r)}:{-umax(\tdplotmaintheta,\R,\r)},smooth,samples=51]
({torusx(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)})
plot[variable=\x,
domain={umax(\tdplotmaintheta,\R,\r)}:{180-umax(\tdplotmaintheta,\R,\r)},smooth,samples=51]
({torusx(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)});
\draw[thick] plot[variable=\x,
domain={-180+umax(\tdplotmaintheta,\R,\r)/2}:{-umax(\tdplotmaintheta,\R,\r)/2},smooth,samples=51]
({torusx(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusy(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)},
{torusz(\x,vcrit2(\x,\tdplotmaintheta),\R,\r)});
\draw[thick,dashed]
plot[smooth,variable=\x,domain={360+vcrit1(\X,\tdplotmaintheta)}:{vcrit2(\X,\tdplotmaintheta)},samples=71]
({torusx(\X,\x,\R,\r)},{torusy(\X,\x,\R,\r)},{torusz(\X,\x,\R,\r)});
\draw[thick]
plot[smooth,variable=\x,domain={vcrit2(\X,\tdplotmaintheta)}:{vcrit1(\X,\tdplotmaintheta)},samples=71]
({torusx(\X,\x,\R,\r)},{torusy(\X,\x,\R,\r)},{torusz(\X,\x,\R,\r)});
\end{tikzpicture}}
\end{document}


The current limitations are:

1. The theta angle has to be larger than 90 degrees and large enough that the torus has hole. (This restriction has been lifted in this post.)
2. The phi angle is 0. This is not a true limitation because of the symmetry of the torus. It could be overcome by shifting all \v values by minus \tdplotmainphi, if this is necessary (but at this point I do not see a motivation for this).

With all these preparations we can tackle the second part of the question, namely how to achieve a shading. As long as one does not insist on a realistic shading, one can use e.g. this answer. The main purpose of this discussion is not the shading, but the question how to use the above with pgfplots. To my own surprise it is absolutely straightforward. This is because pgfplots is extremely well written and all the necessary angles are stored in pgf keys.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\tikzset{declare function={torusx(\u,\v,\R,\r)=cos(\u)*(\R + \r*cos(\v));
torusy(\u,\v,\R,\r)=(\R + \r*cos(\v))*sin(\u);
torusz(\u,\v,\R,\r)=\r*sin(\v);
vcrit1(\u,\th)=atan(tan(\th)*sin(\u));% first critical v value
vcrit2(\u,\th)=180+atan(tan(\th)*sin(\u));% second critical v value
disc(\th,\R,\r)=((pow(\r,2)-pow(\R,2))*pow(cot(\th),2)+%
pow(\r,2)*(2+pow(tan(\th),2)))/pow(\R,2);% discriminant
umax(\th,\R,\r)=ifthenelse(disc(\th,\R,\r)>0,asin(sqrt(abs(disc(\th,\R,\r)))),0);
}}
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\R}{4}
\pgfmathsetmacro{\r}{1}
\begin{axis}[colormap/blackwhite,
view={30}{60},axis lines=none
]
samples=61, point meta=z+sin(2*y),
domain=0:360,y domain=0:360,
z buffer=sort]
({torusx(x,y,\R,\r)},
{torusy(x,y,\R,\r)},
{torusz(x,y,\R,\r)});
\pgfplotsinvokeforeach{300,360}{%
\draw[thick,dashed]
plot[smooth,variable=\x,domain={360+vcrit1(#1-\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})}:{vcrit2(#1-\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})},samples=71]
({torusx(#1-\pgfkeysvalueof{/pgfplots/view/az},\x,\R,\r)},{torusy(#1-\pgfkeysvalueof{/pgfplots/view/az},\x,\R,\r)},{torusz(#1-\pgfkeysvalueof{/pgfplots/view/az},\x,\R,\r)});
\draw[thick]
plot[smooth,variable=\x,domain={vcrit2(#1-\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})}:{vcrit1(#1-\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})},samples=71]
({torusx(#1-\pgfkeysvalueof{/pgfplots/view/az},\x,\R,\r)},{torusy(#1-\pgfkeysvalueof{/pgfplots/view/az},\x,\R,\r)},{torusz(#1-\pgfkeysvalueof{/pgfplots/view/az},\x,\R,\r)})
node[below]{$C\ifnum#1=360 '\fi$};
}
\draw[thick] plot[smooth,variable=\x,domain=60:420,samples=71]
({torusx(25+15*cos(\x),80+45*sin(\x),\R,\r)},
{torusy(25+15*cos(\x),80+45*sin(\x),\R,\r)},
{torusz(25+15*cos(\x),80+45*sin(\x),\R,\r)})
node[above left]{$C''$};
\end{axis}
\end{tikzpicture}
\end{document}


• Marmot perhaps yours and tex.stackexchange.com/questions/119386/… could be combined with tex.stackexchange.com/questions/348/… P.S. I also gave a minor tweak to tex.stackexchange.com/questions/428394/shading-a-torus-in-tikz beware I got borderline memory failures with your choice of 60 samples on the other one and this one has 61 samples which also failed for me unless dropping to 50 samples but it may differ for each users distro settings – user170109 Mar 10 '19 at 0:27
• @KJO I am afraid I cannot combine this with asymptote code. And yes, the memory limitations are unfortunate. One may only draw the visible parts to save a bit. – user121799 Mar 10 '19 at 0:42
• marmot I was not comparing just suggesting that all toroid answers end up as how do I draw "my" thoughts of a toroid irrespective of building technique thankfully no one has dared ask for a 3,8 knot or did I? – user170109 Mar 10 '19 at 0:47
• @KJO Not yet. But 3.8 knots seem to be more feasible than 4-\varepsilon dimensions for noninteger \varepsilon. ;-) – user121799 Mar 10 '19 at 0:53
• That sound like a painful condition is it catching :-) – user170109 Mar 10 '19 at 0:55