# Plotting a contour on a torus

There are two ways to consider a two-dimensional torus. One way is to take a parallelogram (let's say the square $[0, 1]^2$) and topologically glue the opposite edges. Another way is to look at the surface of a doughnut with one hole.

I would like to draw the zero set of a doubly-periodic function as a contour on a torus. Here is how I do it when viewing the torus as a square:

However, I'd really like to see a contour on the surface of a doughnut. How can this be done? (Generally, I'd like to transplant the square $[0, 1]^2$ of any graphic onto the surface of a doughnut.)

-

You could also use MeshFunctions option to map the $[0,1]^2$ region:

yourFunc = Function[{u, v},
Re[2 Exp[2 π I (u + 2 v)] + 3 Exp[2 π I (u - 2 v)]]
];

ParametricPlot3D[{
(2 + Cos[2 π v]) Sin[2 π u],
(2 + Cos[2 π v]) Cos[2 π u],
Sin[2 π v]},
{u, 0, 1}, {v, 0, 1},
MeshFunctions -> Function[{x, y, z, u, v}, yourFunc[u, v]],
Mesh -> {{0}}, (* Because you state yourFunc[u,v] = 0 *)
MeshStyle -> Directive[Blue, Thick],
PlotPoints -> 50
]


Another fancy example:

ParametricPlot3D[{
(3 + Cos[2 π v]) Sin[2 π u],
(3 + Cos[2 π v]) Cos[2 π u],
Sin[2 π v]},
{u, 0, 1}, {v, 0, 1},
MeshFunctions -> Function[{x, y, z, u, v}, yourFunc[v, u]],
Mesh -> {Range[-1, 1, .1]},
MeshStyle -> None,
ColorData["Rainbow"] /@ Rescale[Most@Range[-1, 1, .1]],
{None}],
PlotPoints -> 100,
PlotStyle -> None,
Lighting -> "Neutral"
]


-

One easy way is to use the Line's from your parametric curves and map them onto a torus mathematically. What basically happens here is that we interpret the points of your plot no longer as Cartesian coordinates but as angles $\phi$ and $\theta$ of the torus parametrisation. Here the function for this parametrisation:

With[{rr = 3, r = 1},
torus[{u_, v_}] := {(rr + r*Cos[2 Pi u])*Cos[2 Pi v],
(rr + r*Cos[2 Pi u])*Sin[2 Pi v], r*Sin[2 Pi u]}
]


rr is the inner radius and r the radius of the tube. Now let's take your plot and do the transformation. In the following code, all the magic happens at where I extract the lines of gr using Cases and then transform them into Tube's using our torus function.

gr = ContourPlot[Re[2 Exp[2 Pi I (x + 2 y)] + 3 Exp[2 Pi I (x - 2 y)]] == 0,
{x, 0, 1}, {y, 0, 1}];
Show[
ParametricPlot3D[torus[{u, v}], {u, 0, 1}, {v, 0, 1},
PlotStyle -> Directive[Opacity[.3], Red], Mesh -> None],
Graphics3D[{Blue,
Cases[Normal[gr], Line[__], Infinity] /.
Line[pts_] :> Tube[torus /@ pts]}]
]


-
How do you extend your code to introduce double helix inside the torus? Please see demonstrations.wolfram.com/DoubleHelix – thils Sep 4 '14 at 6:34

For some applications, it might be useful not to use the conventional parametrization of the torus. In particular, if one wants a conformal (angle-preserving) map from a rectangular domain to a torus, one can use the parametric equations (see e.g. Sullivan's paper):

$$\mathbf r(u,v)=\frac1{\sqrt{s^2+t^2}-t\cos\tfrac{2\pi v}{t}}\begin{pmatrix}s\cos\tfrac{2\pi u}{s}\\s\sin\tfrac{2\pi u}{s}\\t\sin\tfrac{2\pi v}{t}\end{pmatrix}$$

with parameter ranges $0\leq u\leq s,\; 0\leq v\leq t$ to conformally map an $s\times t$ rectangle onto a torus.

In particular, for your curve of interest, we can do something similar to Silvia's proposal, but using this parametrization instead. If you want to see the curve only, without the torus backdrop, you can do this:

With[{s = 1, t = 1},
ParametricPlot3D[{s Cos[2 π u/s], s Sin[2 π u/s], t Sin[2 π v/t]}/
(Sqrt[s^2 + t^2] - t Cos[2 π v/t]),
{u, 0, s}, {v, 0, t}, Mesh -> {{0}},
MeshFunctions -> Function[{x, y, z, u, v},
Re[2 Exp[2 π I (u + 2 v)] + 3 Exp[2 π I (u - 2 v)]]],
MeshStyle -> Directive[Thick, Blue],
PlotPoints -> 55, PlotStyle -> None]]


(Change s and t if you want a plot over a wider rectangle.)

If you want to see the torus as well, you can have it be translucent, so that you can still see the structure of the curve. For instance, here's the resulting picture with the setting PlotStyle -> Opacity[3/5, ColorData["Legacy", "PowderBlue"]]:

-
+1 for the math teaching and the reference. – Silvia Jun 10 '13 at 14:04
(As a tiny note: a lot of my previous Gravatars that were based on mapping parallelogram domains to tori used this parametrization. For instance, here is a conformal hexagonal tiling of a torus. Note that the 120° angles of the hexagons are preserved.) – J. M. Jun 10 '13 at 14:05
What previous gravatars of 0x4A4D? This chap's new here... – R. M. Jun 10 '13 at 14:16
(whistles innocently) Uh... right. – J. M. Jun 10 '13 at 14:41

One way to do this is to map the image of the function onto the surface of the torus. First, let's make your plot of the function into an image:

img = Erosion[Image[
ContourPlot[3 Cos[2 \[Pi] (u - 2 v)] + 2 Cos[2 \[Pi] (u + 2 v)] == 0,
{u, 0, 1}, {v, 0, 1}, Frame -> None]], 1]


and map it onto the surface of a torus:

colorfun = BSplineFunction[ImageData[img], SplineDegree -> 1];
ParametricPlot3D[
{(2 + Cos[2 Pi v]) Cos[2 Pi u], (2 + Cos[2 Pi v]) Sin[2 Pi u], Sin[2 Pi v]},
{u, 0, 1}, {v, 0, 1}, ColorFunction -> {colorfun[1 - #5, #4] &},
ViewPoint -> {Pi/2, Pi, 1}, PlotPoints -> 200,  Mesh -> None, Axes -> None]


It's a little easier using the new (version 9) Texture command:

ParametricPlot3D[{(2 + Cos[2 Pi v]) Cos[2 Pi u],
(2 + Cos[2 Pi v]) Sin[2 Pi u], Sin[2 Pi v]},
{u, 0, 1}, {v, 0, 1}, PlotStyle -> {Opacity[1], Texture[img]},
PlotPoints -> 100, Mesh -> None, Axes -> None]


Add the option Lighting->"Neutral" to remove the colored shading and get back to the pure white.

-