RAE wrote 09/30/2021 at 11:30 • 5 min read • Like

//  Author: DonEMitchell, Westcliffe, CO
//  Copyright DonEMitchell, Feb. 9, 2019

//  Description: A parameterized torus knot module using calculated XYZ coordinates.
//  Purpose: Generate a hulled-sequence (skinned) of spheres arranged along the path of a torus knot wound on a torus.
//
//      knotRevolutions(p), knotTwists(q)
//      stepDegrees, loopDia
//
//  Caveat:  The torus knot arc hulled-segments are looped from zero to 360, overlapping zero and 360 to close of the torus knot hull.

/// Calculate constant Phi and define pi:
Phi = pow(5,.5)*.5+.5;   // Φ = ϕ = 1.61803399 dot dot dot.
pi = 3.14159265;         // Π  = Π = 3.14159265 dot dot dot.

/////////////////////////////////////////////////////////
///  Set module variables, torus and torus knot       ///
///  parameters to create a golden orthogonal knot**  ///
/////////////////////////////////////////////////////////

/// **A golden orthogonal knot has inner loops of the torus knot
///   crossing the torus plane through the torus hole at a 90 degree
///   separation (orthogonal) from the angle of the outer loops
///   crossing the torus plane.  The torus knot ratio (p,q) is any two
///   neighboring numbers on the Fibonacci sequence, so the torus
///   knot ratio is a Fibonacci approximation of the golden ratio.

///  Set p:q parameters as an adjacent pair of numbers
///  in the Fibonacci sequence:
///  p Divided by q approximates the golden ratio when
//      q = F(n) and
//      p = F(n+4)
// where F(n) equals the nth Fibonnacci number in the Fibonacci sequence.

p = 13; // Helical twists around the torus tube forming the torus surface.
q =  8; // Axial rotations (Z) radially sweeping in the X,Y plane.

///  to powers of the golden ratio. 'Hole' radius = R - r.

R =     pow(Phi,4);    // Torus major radius.
r = R - pow(Phi,0);    // Torus minor radius.
// Fudge r a scooch to adjust torus to proper bury-depth of the knot into the torus.

/// Torus knot appearance parameters:
loopDia     = 2;       // Fatness of the torus knot loop.
stepDegree  = 1;       // for-loop incrementing variable.
fnTorus     = 39;
fnTorusKnot = 4;

phaseCount = 3;
// Default the module to a golden orthogonal torus knot.
module torusKnotXYZ(
p           = 3, // Default parameter values
q           = 2,
R           = 2.61803,
r           = 2.236068,
showTorus   = true,
stepDegree  = 1/2,
loopDia     = .125,
fnTorus     = 39,// Face number of torus.
fnTorusKnot = 4, // Face number for a square loop cross section.
phaseCount  = 1
){

phaseSeparation = 360/phaseCount;

/// R:r Is the major:minor torus radii.
/// p:q Is a ratio of poloidal rotations (around axis) over helical twists through hole.
//scale([10,10,10])
//difference(){
/// A toroidal surface the knot helix winds upon:
rotate_extrude(\$fn=fnTorus)
translate([R,0,0])
circle(r=r, \$fn=fnTorus);

// Build the torus knot.
for(step=[0:stepDegree:360-stepDegree]) {
for(phaseNumber=[0:phaseCount-1]){

// Calculate two points of the knot, loop-wise.
p1 = [ (R + r * cos(q*step)) * cos(p*step),
(R + r * cos(q*step)) * sin(p*step),
r * sin(q*step) ];

step2 = step + stepDegree;
p2 = [ (R + r * cos(q*step2)) * cos(p*step2),
(R + r * cos(q*step2)) * sin(p*step2),
r * sin(q*step2) ];

// Rotate the knot points to their angular position around the axis of the hole.
rotate([0,0,phaseNumber*phaseSeparation])
color("Lime",1)
hull(){
translate(p1)
sphere(r=loopDia*1.4, \$fn=fnTorusKnot);

translate(p2)
sphere(r=loopDia*1.4, \$fn=fnTorusKnot);

}
// End iterated core.

} // End for(phaseNumber).

} // End for(s).

// Build the contra torus knot.
for(step=[0:stepDegree:360-stepDegree]) {
for(phaseNumber=[0:phaseCount-1]){

// Begin iterated core.
p2 = [ (R + r * cos(q*step)) * cos(p*step),
(R + r * cos(q*step)) * sin(p*step),
r * sin(q*step) ];

step2 = step + stepDegree;
p1 = [ (R + r * cos(q*step2)) * cos(p*step2),
(R + r * cos(q*step2)) * sin(p*step2),
E    r * sin(q*step2) ];

rotate([0,0,phaseNumber*phaseSeparation])
// Join the points with a smooth hull.
hull(){
translate(p1)
sphere(r=loopDia, \$fn=fnTorusKnot);

translate(p2)
sphere(r=loopDia, \$fn=fnTorusKnot);
}
// End iterated core.

} // End for(phaseNumber).

} // End for(s).
//} // End differnce(). Uncomment here and above to create a hollow in the torus.
}  // End module torusKnotXYZ().

// Call the torusKnotXYZ() module defined above.
torusKnotXYZ(q=q, p=p, R=R, r=r, loopDia=.2);