# 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:

-
 I feared that this would be the answer. Thank you for your work! – Caramdir Jul 28 '10 at 14:08 @Caramdir: In reaction to the word "feared", I'd point out that the alternative is to work out the exact equations giving the points on the torus tangent to the angle of incidence (solving a tedious set of equations). Given that it's only as good as the medium it'll be displayed on, I think that the simplicity outweighs the inaccuracy. Looking at it now, I'd pull out the edges a little. – Andrew Stacey Jul 28 '10 at 14:18 I hoped someone has already calculated that and put it in a nice tikz extension. But you are right, pictures like this are always intended for illustration anyway, so they do not need to be completely accurate. – Caramdir Jul 28 '10 at 14:24 @Caramdir: For some unknown reason, this one's been bugging me recently. I've found a reasonable set of beziers that draw the outside of the torus when seen from a reasonable range of angles, but the inside has so far eluded me. Any ideas on how to define the inner curve (conceptually, I mean: what properties should it satisfy)? – Andrew Stacey Jun 13 '11 at 21:19 @Andrew: It should be where the direction of projection is tangent to the torus. I finally sat down and did the math: If the torus is parametrized by (φ,ψ) (i.e. given by (R.cos φ + r.cos(φ)*cos(ψ), R.sin(φ) + r.sin(φ).cos(ψ), r.sin(ψ))), and the projection is along the vector (a,b,c), then the lines are the (visible parts of the) solutions to c.sin ψ + (a.cos φ + b.sin φ).cos ψ = 0. Solving for one variable and plotting gives a neat way to draw the torus, except that it also draws the hidden parts of the inner line. – Caramdir Jun 13 '11 at 23:35
show 1 more comment

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.

-
 Looks good, but not quite what I was looking for. It is however always good to know useful tools, so thank you for the links! – Caramdir Jul 28 '10 at 14:15

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}


-
 Can I insert autmatically ticks by at -pi 0 pi etc.? – lazyboy Sep 5 '12 at 22:59 @lazyboy yep, have a look at axis-with-trigonometric-labels-in-pgfplots – cmhughes Sep 6 '12 at 0:15 pst-math must not be loaded and defining viewpoint twice makes no sense – Herbert Sep 6 '12 at 5:58 The OP asked for a silhouette, and not a plot of the torus. – Dror Sep 6 '12 at 7:03 @Herbert thanks for the feedback. Could you clarify- who can I use Pi without pst-math? I also don't understand how I've defined viewpoint twice – cmhughes Sep 6 '12 at 16:11

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}


-
 Unfortunately the object names are not defined in English. – Click Me Sep 8 '12 at 9:19

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)

-
 Thank you, but I am looking for something more like the picture I linked. Shaded images are often not so useful for black-and-white printing. – Caramdir Jul 27 '10 at 13:14

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:

-
 Is my answer the most similar to the sample in question? – Click Me Sep 8 '12 at 13:37

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}

-