4

I want to use tikz to draw something similar to this:

https://www.youtube.com/watch?v=O7qsB5boS7s

That is, we tile the tore with squares, we cut it open, twist it and then glue it back again.

The idea would be to draw 4 torii: a simple square-tiled torus, a cut-open torus, this cut-open torus twisted and then this new tore glued back again.

An example of a cut-open torus would be this:

For the basic torus, I drawed the following:

\begin{tikzpicture}
\useasboundingbox (-3,-1.5) rectangle (3,1.5);
\begin{scope}
\fill[ball color=blue, opacity=0.15] (0,0) ellipse (3 and 1.5);
  \draw (0,0) ellipse (3 and 1.5);
  \clip (0,-1.8) ellipse (3 and 2.5);
  \draw(0,2.2) ellipse (3 and 2.5);
  \clip (0,2.2) ellipse (3 and 2.5);
  \draw (0,-2.2) ellipse (3 and 2.5);
  \fill[white] (0,-2.2) ellipse (3 and 2.5);
\end{scope}
\end{tikzpicture}

However, I dont know how to square-tile it nor do I know how to "cut" it like in the video.

How could I do it? (I think that this could be easier in assymptote than in Tikz but since every other figure I did in this document was based on the torus I drawed in the MWE, I would like to stay in tikz for this drawing.)

2

To give you a start. This draws the open torus and also has the information when a point is on the visible patch: when the torus parameter v is between vcrit1 and vcrit2, where vcrit1 and vcrit2 depend on the torus parameter u and the view angle theta. More explanations can be found in this post.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{60}{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}
\begin{scope}[local bounding box=torus]
\path[tdplot_screen_coords] 
({-(\R+\r)*1cm-\pgflinewidth},{-(\r+\R*cos(\tdplotmaintheta))*1cm-\pgflinewidth})
rectangle ({(\R+\r)*1cm+\pgflinewidth},{(\r+\R*cos(\tdplotmaintheta))*1cm+\pgflinewidth});
\clip
  plot[smooth,variable=\x,domain={vcrit1(310,\tdplotmaintheta)}:{vcrit2(310,\tdplotmaintheta)},samples=71]   
 ({torusx(310,\x,\R,\r)},{torusy(310,\x,\R,\r)},{torusz(310,\x,\R,\r)})
 --
  plot[smooth,variable=\x,domain={vcrit2(280,\tdplotmaintheta)}:{vcrit1(280,\tdplotmaintheta)},samples=71]   
 ({torusx(280,\x,\R,\r)},{torusy(280,\x,\R,\r)},{torusz(280,\x,\R,\r)})
 -| cycle (torus.south west) rectangle (torus.north east)
;
 \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)});
\end{scope}
\draw[thick]
plot[smooth,variable=\x,domain=0:360,samples=71]   
 ({torusx(310,\x,\R,\r)},{torusy(310,\x,\R,\r)},{torusz(310,\x,\R,\r)})
plot[smooth,variable=\x,domain={vcrit2(280,\tdplotmaintheta)}:{vcrit1(280,\tdplotmaintheta)},samples=71]   
 ({torusx(280,\x,\R,\r)},{torusy(280,\x,\R,\r)},{torusz(280,\x,\R,\r)});
\foreach \X in {60,80,100}
{\draw[thick] plot[smooth,variable=\x,domain=280:-50,samples=71] 
({torusx(\x,\X+\x/18,\R,\r)},{torusy(\x,\X+\x/18,\R,\r)},{torusz(\x,\X+\x/18,\R,\r)});}
\end{tikzpicture}
\end{document}

enter image description here

You may want to add a few more grid lines, which can be drawn as in the last loop. You will have to stop them according to their visibility. This can be automatized using the methods of this answer. First an ordinary grid:

\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
vtest(\u,\v,\az,\el)=sin(-vcrit1(\u-\az,\el)+\v);
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);
}}
\pgfplotsset{visible stretch/.style={restrict expr to domain={vtest(atan2(rawy,rawx),%
ifthenelse(veclen(rawx,rawy)>\R,asin(rawz/\r),180-asin(rawz/\r)),\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})}{-0.05:1.1}},
hidden stretch/.style={restrict expr to 
domain={vtest(atan2(rawy,rawx),%
ifthenelse(veclen(rawx,rawy)>\R,asin(rawz/\r),180-asin(rawz/\r)),\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})}{-1.1:0.05}}}
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\R}{4}
\pgfmathsetmacro{\r}{1}
\begin{axis}[colormap/blackwhite,
   view={40}{60},axis lines=none]
%\typeout{el=\pgfkeysvalueof{/pgfplots/view/el},az=\pgfkeysvalueof{/pgfplots/view/az}}     
       \addplot3[surf,shader=interp,
       samples=61, point meta=z+sin(2*y),
       %surf,shader=flat,
       domain=0:330,y domain=0:360,
       z buffer=sort]
       ({torusx(x,y,\R,\r)}, 
        {torusy(x,y,\R,\r)}, 
        {torusz(x,y,\R,\r)});
    \pgfplotsinvokeforeach{0,30,...,330}  
    {\addplot3[samples y=0,domain=0:330,smooth,samples=71,visible stretch]  
        ({torusx(x,#1,\R,\r)}, 
        {torusy(x,#1,\R,\r)}, 
        {torusz(x,#1,\R,\r)});}

    \pgfplotsinvokeforeach{0,30,...,330}  
    {\addplot3[samples y=0,domain=0:360,smooth,samples=71,visible stretch]  
        ({torusx(#1,x,\R,\r)}, 
        {torusy(#1,x,\R,\r)}, 
        {torusz(#1,x,\R,\r)});}
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

Now to your problem:

\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
vtest(\u,\v,\az,\el)=sin(-vcrit1(\u-\az,\el)+\v);
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);
}}
\pgfplotsset{visible stretch/.style={restrict expr to domain={vtest(atan2(rawy,rawx),%
ifthenelse(veclen(rawx,rawy)>\R,asin(rawz/\r),180-asin(rawz/\r)),\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})}{-0.05:1.1}},
hidden stretch/.style={restrict expr to 
domain={vtest(atan2(rawy,rawx),%
ifthenelse(veclen(rawx,rawy)>\R,asin(rawz/\r),180-asin(rawz/\r)),\pgfkeysvalueof{/pgfplots/view/az},\pgfkeysvalueof{/pgfplots/view/el})}{-1.1:0.05}}}
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\R}{4}
\pgfmathsetmacro{\r}{1}
\begin{axis}[colormap/blackwhite,
   view={40}{60},axis lines=none]
%\typeout{el=\pgfkeysvalueof{/pgfplots/view/el},az=\pgfkeysvalueof{/pgfplots/view/az}}     
       \addplot3[surf,shader=interp,
       samples=61, point meta=z+sin(2*y),
       %surf,shader=flat,
       domain=0:330,y domain=0:360,
       z buffer=sort]
       ({torusx(x,y,\R,\r)}, 
        {torusy(x,y,\R,\r)}, 
        {torusz(x,y,\R,\r)});
    \pgfplotsinvokeforeach{0,30,...,330}  
    {\addplot3[very thick,samples y=0,domain=0:330,smooth,samples=71,visible stretch]  
        ({torusx(x,#1+x/12,\R,\r)}, 
        {torusy(x,#1+x/12,\R,\r)}, 
        {torusz(x,#1+x/12,\R,\r)});}

    \pgfplotsinvokeforeach{0,30,...,330}  
    {\addplot3[samples y=0,domain=0:360,smooth,samples=71,visible stretch]  
        ({torusx(#1,x,\R,\r)}, 
        {torusy(#1,x,\R,\r)}, 
        {torusz(#1,x,\R,\r)});}
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • Hi @marmot, using your code from here and this answer, I did a nice torus with all the vertical lines (from the square-tiling). However the horizontal lines you drew here don't become automaticaly dashed like the vertical ones do. How could we do that here? – Gabriel Apr 18 at 17:09
  • 1
    @Gabriel Just to let you know that I fixed the quadrant problem. The correct way to get v from the raw coordinates is ifthenelse(veclen(rawx,rawy)>\R,asin(rawz/\r),180-asin(rawz/\r)). – marmot Apr 27 at 5:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.