TeX - LaTeX

How to draw a torus

Is there an easy way to draw a contour image of torus below with tikz? Or for that matter with any other graphics package.

One fairly easy, but a bit rough-and-ready, would be to load that picture as the background in Inkscape, then draw over the top an SVG version of it, and finally export it to TikZ using the export-tikz plugin.

Actually, for a simple picture like this one you could do it "by hand" in TikZ: use TikZ to draw on top of the picture, adjust the parameters until it looks right, then remove the background.

Other than that, work out the equation of what you're seeing and code that into TikZ. I thought about doing this when I was trying to draw a torus (see my other answer) and decided that I couldn't be bothered to work out the details so would draw a torus "as it was meant to be" (namely, a product of circles).

Edit: Here's the result, a little tweaked afterwards:

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

\draw (-2,.2) .. controls (-1.5,-0.3) and (-1,-0.5) .. (0,-.5) .. controls (1,-0.5) and (1.5,-0.3) .. (2,0.2);

\draw (-1.75,0) .. controls (-1.5,0.3) and (-1,0.5) .. (0,.5) .. controls (1,0.5) and (1.5,0.3) .. (1.75,0);

\end{tikzpicture}


Produced the following:

Anthony Phan wrote a 3d extension of Metapost, m3D, which is well suited to such things. As an example, hoe wrote some code to draw a graph on a Torus (last example):

The downside is that this fork doesn't support nice things like the mptosvg SVG converter, &c, nor the nice Metapost 2 extensions. I seem to recall some discussion of adding 3d support to the mainstream (i.e. Taco Hoekwater stream) Metapost, but I guess that didn't come to anything. But there is some fairly well established 3d drawing support for the regular Metapost language by Dennis Riegel.

You could parametrize the surface as (for example)

x(t,s) = (2+cos(t))*cos(s+pi/2)
y(t,s) = (2+cos(t))*sin(s+pi/2)
z(t,s) = sin(t)


where both t and s take values on [0,2pi] and then use the pgfplots package.

Admittedly, I'm not sure if this package was available at the time when the question was written :)

\documentclass{article}
\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}
colormap/cool,
samples=20,
domain=0:2*pi,y domain=0:2*pi,
z buffer=sort]
({(2+cos(deg(x)))*cos(deg(y+pi/2))},
{(2+cos(deg(x)))*sin(deg(y+pi/2))},
{sin(deg(x))});
\end{axis}
\end{tikzpicture}

\end{document}


Or else with PSTricks

\documentclass{article}
\usepackage{pst-solides3d}
\begin{document}

\begin{pspicture}(-3,-4)(3,6)
\psset{viewpoint=20 40 40 rtp2xyz,Decran=30,lightsrc=20 10 10}
\defFunction[algebraic]{torus}(u,v)
{(2+cos(u))*cos(v+\Pi)}
{(2+cos(u))*sin(v+\Pi)}
{sin(u)}
\psSolid[object=surfaceparametree,
base=-10 10 0 6.28,fillcolor=black!70,incolor=orange,
function=torus,ngrid=60 0.4,
opacity=0.25]
\end{pspicture}

\end{document}


without a grid

\documentclass{minimal}
\usepackage{pst-solides3d}
\pagestyle{empty}
\begin{document}

\begin{pspicture}(-6,-4)(6,4)
\psset{viewpoint=30 0 15 rtp2xyz,Decran=30,lightsrc=viewpoint}
\psSolid[object=tore,r1=5,r0=1,ngrid=36 72,fillcolor=blue!30,grid=false]%
\end{pspicture}

\end{document}


with a grid a colors

\documentclass{article}
\usepackage{pst-solides3d}
\begin{document}

\begin{pspicture}(-3,-4)(3,6)
\psset{Decran=30,viewpoint=20 40 30 rtp2xyz,lightsrc=viewpoint}
\psSolid[object=tore,r1=2.5,r0=1.5,ngrid=18 36,fillcolor=green!30]%
\end{pspicture}

\begin{pspicture}(-3,-4)(3,6)
\psset{Decran=30,viewpoint=20 40 30 rtp2xyz,lightsrc=viewpoint}
\psSolid[object=tore,r1=2.5,r0=1.5,ngrid=18 36,
tablez=0 0.3 1.5 { } for, zcolor=1 0 0 0 1 1]%
\end{pspicture}

\end{document}


I'll see your torus and raise you two more (both SVGs, for PDFs go here and here).

(In general, I'd recommend the http://texample.net page for seeing what's capable with TikZ)

I traced the original image to get the critical points. By setting showgrid to top and commenting out %\rput(0,0){\usebox\IBox}, you can edit the critical points to get a better result that suits your preferences.

\documentclass[pstricks,border=0pt]{standalone}
\usepackage{graphicx}

\def\Columns{10}
\def\Rows{10}
\newsavebox\IBox
\savebox\IBox{\includegraphics{torus.eps}}

\psset
{
xunit=0.5\dimexpr\wd\IBox/\Columns\relax,
yunit=0.5\dimexpr\ht\IBox/\Rows\relax,
}

\begin{document}
\begin{pspicture}[showgrid=false](-\Columns,-\Rows)(\Columns,\Rows)
%\rput(0,0){\usebox\IBox}
\psellipse(9.7,9)
\def\temp{%
\psbezier(0,3.3)(3,3.3)(5,2)(5.4,1.2)
\psbezier(0,-0.5)(3,-0.5)(5,0.5)(5.4,1.2)
\psbezier[linewidth=0.5\pslinewidth,linecolor=lightgray](5.4,1.2)(5.7,1.5)(6.2,2.9)(7.5,3.3)
\pscurve(5.4,1.2)(5.55,1.42)(6.0,2.1)}%
\temp\psscalebox{-1 1}{\temp}
\end{pspicture}
\end{document}


The following is the output:

And the original one:

Along the line of @AndrewStacey, I tried something slightly simpler. Using one ellipse and an two elliptical arcs, translated, I get the (almost) right visual effect, which is not at all accurate:

The code is rather simple and easy to tweak in case one wants to get a better/different visual effect:

\documentclass[tikz,border=5pt]{standalone}
\begin{document}
\begin{tikzpicture}[samples=100]
\def\a{3.2}
\def\b{1.5}
\def\PI{3.14159265359}
\draw[domain=0:2*\PI] plot ({\a*cos(\x r)},{\b*sin(\x r)});
\draw[domain=\PI/4:3*\PI/4] plot ({\a*cos(\x r)},{\b*sin(\x r) -1});
\draw[domain=-0.1+5*\PI/4:0.1+7*\PI/4] plot ({\a*cos(\x r)},{\b*sin(\x r) +1.1});
\end{tikzpicture}
\end{document}