# Modular Transformation in TikZ

I would like to recreate the following image in tikz, without the d part, where the torus a is up in the middle and the torus b and c are under a to the left and right with the T and S arrows pointing to them.

What i got so far is that (based on Drawing Torus with semi-dashed line on it):

\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=white,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 {200}
{\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]{$a$};
}
\end{tikzpicture}
\end{tikzpicture}
\end{document}


Purely for comparison (or, more honestly, for my own mindfulness exercise) here is a version in Metapost, which might be of interest to some users. This is wrapped up in luamplib so you need to compile it with lualatex.

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);

path o, u, a;
o = fullcircle rotated 45 xscaled 89 yscaled 55;
u = subpath (4.1, 7.9) of fullcircle xscaled 45 yscaled 26 shifted 7 up;
a = subpath (0, 4) of fullcircle xscaled 45 yscaled 26 shifted 3 down
cutbefore subpath (2, 4) of u cutafter subpath (0, 2) of u;
path f, g;
f  = buildcycle(point 1 of a {direction 1 of a} .. point 1/16 of u, u, reverse a);
g = buildcycle(o scaled 33/32 rotated 4 shifted (-2, 2), reverse o);

path ring, loop, twist;

ring = o xscaled 0.8 yscaled 0.65 shifted 7.5 up;
loop = reverse fullcircle rotated 90 xscaled 23.25 yscaled 14 rotated 47;
loop := loop shifted (point 4 of o - point 6 of loop);

picture torus; torus = image(
fill f withcolor 7/8;
fill g withcolor 7/8;
draw o;
draw u;
draw a;
);

picture A, B, C;
interim ahangle := 30;
interim ahlength := 3;
A = image(
draw subpath (2, 6) of loop withcolor 7/8[2/3 red, white];
draw subpath (0, 2) of loop withcolor 2/3 red;
drawarrow subpath (6, 8) of loop withcolor 2/3 red;
label.lft("$\scriptstyle a$", point 0 of loop) withcolor 2/3 red;
draw subpath (3.6, 4.3) of ring withpen pencircle scaled 4 withcolor white;
drawarrow subpath (-2, 6) of ring withcolor 2/3 blue;
label.bot("$\scriptstyle b$", point 6 of ring) withcolor 2/3 blue;
draw torus;
);
C = image(
draw subpath (2, 6) of loop withcolor 7/8[2/3 blue, white];
drawarrow subpath (6, -2) of ring withcolor 2/3 red;
label.bot("$\scriptstyle a$", point 6 of ring) withcolor 2/3 red;
draw subpath (0, 1) of loop withpen pencircle scaled 4 withcolor white;
draw subpath (0, 2) of loop withcolor 2/3 blue;
drawarrow subpath (6, 8) of loop withcolor 2/3 blue;
label.lft("$\scriptstyle b$", point 0 of loop) withcolor 2/3 blue;
draw torus;
) shifted 68 down;
twist = subpath (-1.5, 4.2) of ring ... point 4.9 of o {direction 4.9 of o}
.. point 2.8 of u {direction 2.8 of u} .. {direction -1.5 of ring} cycle;
B = image(
draw subpath (2, 6) of loop withcolor 7/8[2/3 red, white];
draw subpath (0, 2) of loop withcolor 2/3 red;
drawarrow subpath (6, 8) of loop withcolor 2/3 red;
label.lft("$\scriptstyle a$", point 0 of loop) withcolor 2/3 red;
draw subpath (3.6, 4.3) of ring withpen pencircle scaled 4 withcolor white;
drawarrow subpath (0, 2) of twist withcolor 2/3 blue;
drawarrow subpath (2, 7.5) of twist withcolor 2/3 blue;
draw subpath (7.5, 8) of twist withcolor 2/3 blue;
drawarrow subpath (8, 8.6) of twist withcolor 7/8[2/3 blue, white];
draw subpath (8.6, 9) of twist withcolor 7/8[2/3 blue, white];
draw subpath (9, length(twist)) of twist withcolor 2/3 blue;
label.urt("$\scriptstyle b$", point 7.4 of twist) withcolor 2/3 blue;
draw torus;
) shifted 110 right;

draw A;
draw B;
draw C;

bboxmargin := -2;
path a[];
a1 = point 1.75 of bbox A {dir 20} .. point 3.25 of bbox B;
a2 = point 0.2 of bbox A {dir 250} .. point 2.8 of bbox C;

drawarrow a1; label.top("$T$", point arctime 1/2 arclength a1 of a1 of a1);
drawarrow a2; label.lft("$S$", point arctime 1/2 arclength a2 of a2 of a2);

bboxmargin := 4;
label("\small\textbf{(a)}", point 3 of bbox A);
label("\small\textbf{(b)}", point 2.8 of bbox B);
label("\small\textbf{(c)}", point 3.2 of bbox C);

endfig;
\end{mplibcode}
\end{document}


This is not a very flexible approach -- which is why for example I had to resort to setting the labels in \scriptstyle. To make it more general, I would have to avoid having so many "magic numbers" and try to scale all the subcomponents relative to the outer ring.

• Also your code...it is very impressive. Commented Nov 28, 2021 at 21:41

Welcome to TeX.SE!!!

That is what I'd do: a \pic for the torus in which I'e add the relevant coordinates (using the calc library). The rest is fine tuning, drawing elliptic arcs or curves (only for c). I use also the decorations.markings library for the arrows at mid-path.

This is my code:

\documentclass[border=2mm,tikz]{standalone}
\usetikzlibrary{calc,decorations.markings}

\tikzset
{%
my arrow/.style={%
decoration={markings,mark=at position #1 with {\arrow{latex}}},
postaction={decorate}
},
pics/torus/.style={
code={%
\coordinate (-O) at (0,0.75);
\coordinate (-A) at ($(-O)+(195:1.75cm and 1cm)$);
\coordinate (-B) at ($(-O)+(210:1.75cm and 1cm)$);
\coordinate (-C) at ($(-O)+(330:1.75cm and 1cm)$);
\coordinate (-D) at (250:3cm and 2cm);
\coordinate (-E) at ($(-O)+(225:1.75cm and 1cm)$);
\coordinate (-F) at (220:3cm and 2cm);
\coordinate (-G) at ($(-O)+(290:1.75cm and 1cm)$);
\coordinate (-H) at (260:3cm and 2cm);
\coordinate (-I) at ($(-O)+(220:2.25cm and 1.125cm)$);
\fill[gray!20] (-A) arc (195:210:1.75cm and 1cm) to [out=35,in=145] (-C) to [out=140,in=30] (-A);
\fill[gray!20] (-D) arc (250:365:3cm and 2cm)    to [out=250,in=10]  cycle;
\draw[very thick,black] (0,0) ellipse (3cm and 2cm);
\draw[very thick,black] (-B) to [out=35,in=145] (-C);
\draw[very thick,black] (-O) + (345:1.75cm and 1cm) arc (345:195:1.75cm and 1cm);
\draw[very thick, opacity=0.3] (-E) to[out=330,in=330] (-F);
\draw[very thick,my arrow=0.6] (-F) to[out=150,in=150] node [pos=0.6,xshift=-4mm] {$#1$} (-E) ;
% uncomment this to see the coordinates:
%        \foreach\i in {A,B,C,D,E,F,G,H,O,I}
%          \fill (-\i) circle (1pt) node [below] {$\i$};
}}
}

\begin{document}
\begin{tikzpicture}[line cap=round]
% torus (a)
\node at (-3,2) {\bfseries (a)};
\pic[draw=red,text=red] (a) at  (0,0) {torus={a}};
\fill[white] (a-I) circle (1mm);
\draw[blue,very thick,my arrow=0.75] (a-O) ellipse (2.25 cm and 1.125 cm) node [pos=0.75,yshift=-6mm] {$b$};
% torus (b)
\node at (4,2) {\bfseries (b)};
\pic[draw=red,text=red]  (b) at  (7,0) {torus={a}};
\fill[white] (b-I) circle (1mm);
\draw[very thick,blue, opacity=0.3] (b-H) to [out=-10,in=190] (b-G);
\draw[very thick,blue,my arrow=0.4] (b-G) to [out=10,in=270]  ($(b-O)+(0:2.25cm and 1.125cm)$)
arc (0:180:2.25cm and 1.125cm) node [pos=0.4,below] {$b$} to [out=270,in=150] (b-I) to[out=330,in=160] (b-H);
% torus (c)
\node at (-10,2) {\bfseries (c)};
\pic[draw=blue,text=blue] (c) at (-7,0) {torus={b}};
\draw[very thick,red,my arrow=0.85] ($(c-O)+(215:2.25cm and 1.125cm)$)
arc (215:-132:2.25cm and 1.125cm) node[pos=0.85,below] {$a$};
% Tranformations
\draw[-latex] (-3,0.5) to[out=150,in=30]  node[midway,above] {$S$} (-4,0.5);
\draw[-latex]  (3,0.5) to[out=30,in=150]  node[midway,above] {$T$}  (4,0.5);
\end{tikzpicture}
\end{document}


And the output:

• Very impressive, as always! +1 Commented Nov 28, 2021 at 19:29
• Thanks, @SebGlav, :D Commented Nov 28, 2021 at 20:59