Thanks to flockaroo's torus turtle torus and the equation from OSX grapher app.
Log in to post a comment.
// created by Andrew Lamoureux (andrewl) - 2018 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. // You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(.25); // Global code will be evaluated once. const turtle = new Turtle(); turtle.pendown() const screen_width = 200 const screen_height = 200 var xrot = Math.PI/3.7 /* in radians */ const scale = 19 const shifty = -19 const shiftx = 4 const ticks_toroid = 100 const ticks_cross_section = 50 const npoints = ticks_toroid * ticks_cross_section function get_knot_point(i) { // point index -> (t, u) ti = Math.floor(i/ticks_cross_section) ui = i % ticks_cross_section t = ti/ticks_toroid * 2*Math.PI u = ui/ticks_cross_section * 2*Math.PI // eval parametric equations -> polar coords r0 = scale*(3 + msin(t) + mcos(u)) theta = 2*t z = scale*(msin(u) + 2*mcos(t)) // polar -> cartesian x = r0*mcos(theta) + shiftx y = r0*msin(theta) + shifty return [x,y,z] } // The walk function will be called until it returns false. function walk(i) { // this point pi = get_knot_point(i) // next point in this cross section if((i+1) % ticks_cross_section == 0) pj = get_knot_point(i-ticks_cross_section+1) else pj = get_knot_point(i+1) // point in next cross section p3 = get_knot_point(i+ticks_cross_section) pi = rotX(xrot,pi) pj = rotX(xrot,pj) p3 = rotX(xrot,p3) pi = project(pi) pj = project(pj) p3 = project(p3) turtle.penup() turtle.goto(p3[0], p3[1]) turtle.pendown() turtle.goto(pi[0], pi[1]) turtle.goto(pj[0], pj[1]) turtle.goto(p3[0], p3[1]) // compute vector perpendicular to their plane and test if z coord is positive (facing us) // or negative (facing away) if(vec3_cross(vec3_sub(pj,pi), vec3_sub(p3,pi) )[2] > 0.0) { for(k in [1,2,3]) { turtle.penup() turtle.goto(p3[0], p3[1]) turtle.pendown() turtle.goto(pi[0], pi[1]) turtle.goto(pj[0], pj[1]) turtle.goto(p3[0], p3[1]) } } return i<npoints } function project(p) { x = p[0] y = p[1] z = p[2] z = z + 180 return [ (x/z)*screen_width, (y/z)*screen_height ]; } function mcos(x) { return Math.cos(x); } function msin(x) { return Math.sin(x); } function vec3_add(a,b) { return [a[0]+b[0],a[1]+b[1],a[2]+b[2]]; } function vec3_sub(a,b) { return [a[0]-b[0],a[1]-b[1],a[2]-b[2]]; } function vec3_cross(a,b) { return [ a[1]*b[2]-b[1]*a[2], a[2]*b[0]-b[2]*a[0], a[0]*b[1]-b[0]*a[1] ]; } function rotX(ph,v) { return [ v[0],v[1]*mcos(ph)+v[2]*msin(ph), v[2]*mcos(ph)-v[1]*msin(ph) ]; }