I propose a small modification of the parametrization for the torus that addresses issues with conformality. Try
F[t_, u_, r_] := {Cos[t] (r + Cos[u + Sin[u]/r]),
Sin[t] (r + Cos[u + Sin[u]/r]),
Sin[u + Sin[u]/r]}
instead. Next, we wish to choose suitable values for $m, n$ for a given $r$ such that the mapping of the regular hexagonal tiling preserves angles as much as possible. We see that this requires us to choose $m, n$ such that $$\frac{\sqrt{3}}{2} \frac{n}{m} = r.$$ As we also require $n$ to be even (or else the tiling does not fit properly on the torus), we can let $n = 2k$ and this gives us $k \sqrt{3} = rm$; thus for a given $r$ we should try to choose $k, m$ as the nearest integers satisfying this equation. This gives us a very nearly angle-preserving tiling. For example, with $r = 2 \sqrt{3}$, we can choose $m = 11$, $n = 44$ to get something that looks like this:
Notice how much more regular the hexagons are throughout the torus--the "inner" ones are not squashed, and the outer ones are not stretched.
Addendum. So, the above seems to work reasonably well for large $r$, but when $r = 1 + \epsilon$ for small $\epsilon$, it doesn't work because the mapping I chose is not truly conformal. I found the relevant information here.
This suggests that the correct form of $f$ should be
F[t_, u_, r_] := {Cos[t], Sin[t], Sin[# u]/#} #^2/(r - Cos[# u]) &[Sqrt[r^2 - 1]]
And whereas $t$ is still plotted on the same interval, we need to plot $u$ on $\left(-\frac{\pi}{\sqrt{r^2-1}}, \frac{\pi}{\sqrt{r^2-1}}\right)$. So we modify the plotting command as well:
P[r_, m_, n_] := Graphics3D[Polygon /@
Table[F[4 Pi/(3 n) (Cos[Pi k/3] + i 3/2),
2 Pi/(Sqrt[3 (r^2 - 1)] m) (Sin[Pi k/3] + (j + i/2) Sqrt[3]),
r], {i, n}, {j, m}, {k, 6}], Boxed -> False]
And now the selection of $m, n$ based on $r$ is also more complicated. $n = 2m \sqrt{\frac{r^2 - 1}{3}}$ seems to give good results. Here is a picture for $r = 1.1$, $m = 30$, $n = 20$:
This solution calculates exact coordinates. However, for 3D-printing, machine precision is usually enough, and affords a significant speedup. We can force machine arithmetic by adding dots after some of the constants (e.g. 2 Pi
to 2. Pi
). We can also achieve a 3× speed up by only calculating the location of each vertex once, and using GraphicsComplex
to share the locations with each hexagon. (This is how 3D formats like .stl
work internally. If you need regular polygon objects to process further, just use Normal
to eliminate GraphicsComplex
.)
Pfast[r_, m_, n_] :=
Graphics3D[
GraphicsComplex[
Flatten[Table[
F[2. Pi (i + k/3.)/n, Pi (1. + i + 2 j)/m/Sqrt[r^2 - 1.],
r // N], {j, m}, {i, n}, {k, {-1, +1}}], 2],
Polygon[Join @@
Table[Mod[(j - 1) (2 n) + {1, 2, 3 + If[i == n, n (n - 2), 0]}~
Join~({2, 1, If[i == 1, n (2 - n), 0]} + 2 n) + 2 (i - 1),
2 n m, 1], {i, n}, {j, m}]]], Boxed -> False]
The code is almost the same as before, except that we now only need to generate two new coordinates for each cell, so Cos[Pi k/3]
only takes on two values and Sin[Pi k/3]
only takes on one value, allowing the arithmetic to be simplified considerably. We don't need to change F
; it's already extremely fast due to the two-stage calculation it does to avoid recomputing the expensive square root multiple times.
We can do a timing and memory usage comparison of the two versions:
ByteCount[P2[2, 50, 100]] // Timing
(* {0.343750, 1440448} *)
ByteCount[P[2, 50, 100]] // Timing
(* {5.921875, 60849648} *)
The numerical version is around 20 times faster and gives a result 40 times smaller. It's actually now fast enough to quickly make a nice table of tori with different parameters:
GraphicsGrid[
ParallelTable[
With[{n = 2 Round[m Sqrt[(r^2 - 1)/3]]},
Show[P2[r, m, n], PlotLabel -> {r, m, n}]], {r, {1.1, 1.5, 2, 3,
5}}, {m, {6, 10, 15, 20, 30, 50}}], ImageSize -> Full]