Jump to my Home Page Send me a message Check out stuff on GitHub Check out my photography on Instagram Check out my profile on LinkedIn Check me out on Facebook

Torus Knots

small 2 3 torus knot small 3 2 torus knot
small 2 5 torus knot small 5 2 torus knot
small 2 7 torus knot small 3 7 torus knot
small 3 7 torus knot small 3 7 torus knot
small 3 5 torus knot small 3 5 torus knot
small 5 7 torus knot small 3 7 torus knot

How The Images Were Made

Create the Geometry

The first task is to generate the geometric description of the objects our 3D rendering engine will draw. Our knots are curves, but curves are 1D objects -- 3D rendering tools don't render 1D objects, they render 3D objects. So instead of generating a geometric description of a curve, we create a "tube" -- a fat curve with some thickness. Many ways exist to do that, but the one I selected for this application is what I call the "ball and cylinder" technique. The idea is to sample the curve along a regularly spaced grid, draw a sphere at each sample point, and connect the spheres together with cylinders. As a side note, this is the kind of geometric structure my LISP calculator program produces as well. While it would have been less difficult for me to use the LISP calculator, I think it would have made it more difficult for the people reading this. :) So, I used the ruby programming language.

While two scripts may be found in this section, only the first one was used for the images above. The scripts can do a bit more than is demonstrated here. They can dump CSV-style data that may be imported into graphing packages, draw sphere sweep-like geometries instead of ball-n-cylinder, and can add arrows to the curves.

The mkTorusKnot.rb is used to generate a file, tordat.txt, that is used by the rendering tool in the next step. Here is a code snip showing how we do it:
           ./mkTorusKnot.rb 5 2 1 3 1000 pcyl > tordat.txt
         
For additional details regarding the script arguments and usage, consult the comments at the top of the scripts and the examples in the section Automating the whole thing.

Render the 3D scene

The geometric object is rendered using POV-Ray. All of the above images are generated with a single POV-Ray source file that "includes" the output of the mkTorusKnot.rb script placed into a file named tordat.txt. The POV-Ray input file is torus_knot.pov, and here is how we use it:

           povray -D -P -W800 -H600 -Q11 +A0.4 -AM2 -R5 +Itorus_knot.pov +Otorus_knot.png
           rm tordat.txt
         
After the above commands run, the image will be in a file called torus_knot.png

Annotate and create thumbnail

The tool here is ImageMagick. We use a larger font that one might normally expect because we immediately shrink the image down by 50%.
        s0="gravity northwest fill black text 1,11 'Torus Knot ($p,$q)'"
        convert torus_knot.png  -pointsize 40 -draw "$s0" -resize 50% torus_knot_small.gif
      

Annotate and compost with a gradient background

We need to annotate the big images, but we also need to do something about the background. All of my image wrapper pages have a black background, but the images here have a white background -- my wife says they look better that way. So the goal is to fade that white background to black so that we don't have a stark white/black transition on the page. We start by creating a white to black, non-linear, radial gradient image with the appropriate aspect ratio. Then we compost the background image with the torus knot image, and then annotate the result. As with the thumbnails, we use ImageMagick for this too:

           convert -size 800x800 radial-gradient: -sigmoidal-contrast 12,2% -resize 800x600\! f.png
           composite -gravity center torus_knot.png -compose Multiply f.png tmp.png
           s1="gravity northwest fill white text 1,11 'Torus Knot ($p,$q)'"
           s2="gravity southeast fill white text 1,11 'By Mitch Richling'"
           convert tmp.png -pointsize 20 -draw "$s2" -draw "$s1" torus_knot_big.gif
           rm f.png tmp.png
         

Automating the whole thing

It would be a real pain to do the above steps for each image manually, so we automate the process for all the torus knots above with a little bash script. You can download the script here, or take a look at it below:

           #!/bin/bash
           # Create the gradient background we will use for the big images
           convert -size 800x800 radial-gradient: -sigmoidal-contrast 12,2% -resize 800x600\! f.png
           for p in 2 3 5 7 11; do
             for q in 2 3 5 7 11; do
               if [ $p != $q ]; then
                 echo $p $q
                 POVOPT=' -Q11 +A0.4 -AM2 -R5 '
                 # Uncomment the next line for faster renders
                 #POVOPT=' '
                 # Generate the knot geometry
                 ./mkTorusKnot.rb $p $q 1 3 1000 pcyl > tordat.txt
                 # Render the image into a PNG file
                 povray -D -P -W800 -H600 $POVOPT +Itorus_knot.pov +Otorus_knot_${p}_${q}.png
                 rm tordat.txt
                 # Create the thumbnail by annotating the image and reducing the size
                 s0="gravity northwest fill black text 1,11 'Torus Knot ($p,$q)'"
                 convert torus_knot_${p}_${q}.png  -pointsize 40 -draw "$s0" -resize 50% torus_knot_${p}_${q}_small.gif
                 # Create the big image by composting a gradient background and annotating the image
                 s1="gravity northwest fill white text 1,11 'Torus Knot ($p,$q)'"
                 s2="gravity southeast fill white text 1,11 'By Mitch Richling'"
                 composite -gravity center torus_knot_${p}_${q}.png -compose Multiply f.png tmp.png
                 convert tmp.png  -pointsize 20 -draw "$s2"   -draw "$s1" torus_knot_${p}_${q}_big.gif
                 rm tmp.png
               fi
             done
           done
           # Delete the gradient background image
           rm f.png        
           # Display the images
           pqiv -f `ls torus_knot_*.png torus_knot_*_big.gif | sort` torus_knot_*_small.gif 
         

More example images

Here are some examples illustrating "hoops" that one can make with mkTorusHoops.rb, curves offset from the torus, and arrows. The thumbnails below don't link to larger images.

small 2 3 torus knot small 3 2 torus knot
small 2 3 torus knot small 3 2 torus knot
© 2009 Mitch Richling