Drawing a torus with POV-Ray

Posted on June 2, 2018 by Stéphane Laurent

It is easy to draw a torus with POV-Ray. What we propose here, is to draw a torus such that its equator passes by three given points.

The include file analytical_g.inc made by Friedrich A. Lohmueller provides a macro which does this task, namely the macro Circle_Line_out. However I tested it and I noticed that the rendering is very slow. With the macro I wrote, provided below, the rendering is not slow.

// -------------------------- the Torus macro ------------------------------- //
    // 3x3 matrix Functions ----------------------------------------------------
#macro det(A)
    - A[0].z*A[1].y*A[2].x
    + A[0].y*A[1].z*A[2].x
    + A[0].z*A[1].x*A[2].y
    - A[0].x*A[1].z*A[2].y
    - A[0].y*A[1].x*A[2].z
    + A[0].x*A[1].y*A[2].z
#end
#macro transpose(A)
    array[3] { < A[0].x,A[1].x,A[2].x >,
               < A[0].y,A[1].y,A[2].y >,
               < A[0].z,A[1].z,A[2].z > }
#end
#macro Inverse(A)
    #local d=det(A);
    array[3] {
     < -A[1].z*A[2].y+A[1].y*A[2].z,
       A[0].z*A[2].y-A[0].y*A[2].z,
       -A[0].z*A[1].y+A[0].y*A[1].z > / d,
     < A[1].z*A[2].x-A[1].x*A[2].z,
       -A[0].z*A[2].x+A[0].x*A[2].z,
       A[0].z*A[1].x-A[0].x*A[1].z > / d,
     < -A[1].y*A[2].x+A[1].x*A[2].y,
       A[0].y*A[2].x-A[0].x*A[2].y,
       -A[0].y*A[1].x+A[0].x*A[1].y > / d
    }
#end
#macro mult(A,p)
    < A[0].x*p.x+A[0].y*p.y+A[0].z*p.z,
      A[1].x*p.x+A[1].y*p.y+A[1].z*p.z,
      A[2].x*p.x+A[2].y*p.y+A[2].z*p.z >
#end
    // Transformation matrix ---------------------------------------------------
#macro Matrix(p)
    #local a = p.x;
    #local b = p.y;
    #local c = p.z;
    #if(a=0 & c =0)
        matrix < 1, 0, 0,
                 0, 1, 0,
                 0, 0, 1,
                 0, 0, 0 >
    #else
        #local length = vlength(p);
        #local aa = a/length;
        #local bb = b/length;
        #local cc = c/length;
        #local n = <aa, bb, cc>;
        #local s = sqrt(aa*aa+cc*cc);
        #local aaa = aa/s;
        #local ccc = cc/s;
        #local uu = < -ccc, 0, aaa>;
        #local vv = vcross(n,uu);
        matrix < -ccc, 0,    aaa,
                 aa,   bb,   cc,
                 vv.x, vv.y, vv.z,
                 0,    0,    0 >
    #end
#end
    // plane passing by points p1, p2, p3 --------------------------------------
#macro Plane1(p1,p2,p3)
    #local xcoef = (p1.y-p2.y)*(p2.z-p3.z)-(p1.z-p2.z)*(p2.y-p3.y);
    #local ycoef = (p1.z-p2.z)*(p2.x-p3.x)-(p1.x-p2.x)*(p2.z-p3.z);
    #local zcoef = (p1.x-p2.x)*(p2.y-p3.y)-(p1.y-p2.y)*(p2.x-p3.x);
    #local Offset = p1.x*xcoef + p1.y*ycoef + p1.z*zcoef;
    <xcoef, ycoef, zcoef, Offset>
#end
    // plane passing by p & perpendicular to norm ------------------------------
#macro Plane2(p,norm)
  #local Offset = p.x*norm.x+p.y*norm.y+p.z*norm.z;
  <norm.x, norm.y, norm.z, Offset>
#end
    // Circumcenter and circumradius of the circle passing by p1,p2,p3 ---------
#macro CircleCenter(p1,p2,p3)
    #local p12 = (p1+p2)/2;
    #local p23 = (p2+p3)/2;
    #local v12 = p2-p1;
    #local v23 = p3-p2;
    #local plane1 = Plane1(p1,p2,p3);
    #local plane2 = Plane2(p12,v12);
    #local plane3 = Plane2(p23,v23);
    #local A = array[3] { <plane1.x, plane2.x, plane3.x>,
                          <plane1.y, plane2.y, plane3.y>,
                          <plane1.z, plane2.z, plane3.z> };
    #local b = <plane1.t, plane2.t, plane3.t>;
    #local center = mult(Inverse(transpose(A)),b);
    #local op1 = p1-center;
    #local r = vlength(op1);
    <center.x, center.y, center.z, r>
#end
    // Torus passing by three points -------------------------------------------
#macro Torus(p1,p2,p3,r,Texture)
    #local centre = CircleCenter(p1,p2,p3);
    #local center = <centre.x,centre.y,centre.z>;
    #local R = centre.t;
    #local plane1 = Plane1(p1,p2,p3);
    torus {
      R, r
      texture { Texture }
      Matrix(<plane1.x, plane1.y, plane1.z>)
      translate center
    }
#end
// end of Torus macro ------------------------------------------------------- //

Let me give an example now. I take a tetrahedron and I draw the torus passing by the three vertices of a face, for each of the four faces.