scale(Scale) {
    spath=smooth(Path,Depth); 
    if (Construction=="poly") {
        knot= path_knot(spath,R,Sides,Kscale,Phase,Base,Open_ended=="on");
//       echo(knot);
         show_solid(knot);
        }
    else if (Construction=="hull") {
        $fn=Sides;
        hulled_path(spath,R,Open_ended);
    }
    else if (Construction=="tile") {
       polygon(3d_to_2d(spath));
    }
    else if (Construction=="2D") {
        $fn=Sides;
        2D_hulled_path(spath,R,Open_ended);
    }
        
    else echo("no Construction");
  }
// polyhedron constructor
function poly(name,vertices,faces,debug=[],partial=false) = 
    [name,vertices,faces,debug,partial];
function p_name(obj) = obj[0];
function p_vertices(obj) = obj[1];
function p_faces(obj) = obj[2];
  
module show_solid(obj) {
    polyhedron(p_vertices(obj),p_faces(obj),convexity=10);
};
// utility functions  
function m_translate(v) = [ [1, 0, 0, 0],
                            [0, 1, 0, 0],
                            [0, 0, 1, 0],
                            [v.x, v.y, v.z, 1  ] ];
                            
function m_rotate(v) =  [ [1,  0,         0,        0],
                          [0,  cos(v.x),  sin(v.x), 0],
                          [0, -sin(v.x),  cos(v.x), 0],
                          [0,  0,         0,        1] ]
                      * [ [ cos(v.y), 0,  -sin(v.y), 0],
                          [0,         1,  0,        0],
                          [ sin(v.y), 0,  cos(v.y), 0],
                          [0,         0,  0,        1] ]
                      * [ [ cos(v.z),  sin(v.z), 0, 0],
                          [-sin(v.z),  cos(v.z), 0, 0],
                          [ 0,         0,        1, 0],
                          [ 0,         0,        0, 1] ];
                            
function vec3(v) = [v.x, v.y, v.z];
function transform(v, m)  = vec3([v.x, v.y, v.z, 1] * m);
                            
function orient_to(centre,normal, p) = m_rotate([0, atan2(sqrt(pow(normal.x, 2) + pow(normal.y, 2)), normal.z), 0]) 
                     * m_rotate([0, 0, atan2(normal[1], normal[0])]) 
                     * m_translate(centre);
function 3d_to_2d(path) = [for (p=path) [p.x,p.y]];
// solid from path
function circle_points(r, sides,phase=45) = 
    let (delta = 360/sides)
    [for (i=[0:sides-1]) [r * sin(i*delta + phase), r *  cos(i*delta+phase), 0]];
function loop_points(step,min=0,max=360) = 
    [for (t=[min:step:max-step]) f(t)];
function transform_points(list, matrix, i = 0) = 
   [for (p = list)
       transform(p, matrix)
   ];
function tube_pointsx(loop, circle_points,  i = 0) = 
    (i < len(loop) - 1)
     ?  concat(transform_points(circle_points, orient_to(loop[i], loop[i + 1] - loop[i] )), 
               tube_points(loop, circle_points, i + 1)) 
     : transform_points(circle_points, orient_to(loop[i], loop[0] - loop[i] )) ;
function flatten(l) = [ for (a = l) for (b = a) b ] ;
    
function tube_points(loop, circle_points) = 
    flatten([for (i=[0:len(loop)-1])
        transform_points(
           circle_points, 
           orient_to(loop[i], loop[(i + 1)%len(loop)] - loop[i] ))
    ]);
function loop_faces(segs, sides, open=false) = 
   open 
     ?  concat(
         [[for (j=[sides - 1:-1:0]) j ]],
         [for (i=[0:segs-3]) 
          for (j=[0:sides -1])  
             [ i * sides + j, 
               i * sides + (j + 1) % sides, 
              (i + 1) * sides + (j + 1) % sides, 
              (i + 1) * sides + j
             ]
        ] ,   
        [[for (j=[0:1:sides - 1]) (segs-2)*sides  + j]]
        )
     : [for (i=[0:segs-1]) 
        for (j=[0:sides -1])  
         [ i * sides + j, 
          i * sides + (j + 1) % sides, 
          ((i + 1) % segs) * sides + (j + 1) % sides, 
          ((i + 1) % segs) * sides + j
         ]   
       ]  
     ;
//  path with hulls
module hulled_path(path,r,open) {
    last = open=="on" ? len(path) - 2 :len(path) -1;
    for (i = [0 : 1 : last ]) {
        hull() {
            translate(path[i]) sphere(r);
            translate(path[(i + 1) % len(path)]) sphere(r);
        }
    }
};
module 2D_hulled_path(path,r,open) {
    last = open=="on" ? len(path) - 2 :len(path) -1;
    for (i = [0 : 1 : last ]) {
        hull() {
            translate(path[i]) circle(r);
            translate(path[(i + 1) % len(path)]) circle(r);
        }
    }
};
// smoothed path by interpolate between points 
weight = [-1, 9, 9, -1] / 16;
function interpolate(path,n,i) =
        path[(i + n - 1) %n] * weight[0] +
        path[i]             * weight[1] +
        path[(i + 1) %n]    * weight[2] +
        path[(i + 2) %n]    * weight[3] ;
function subdivide(path,i=0) = 
    i < len(path) 
     ? concat([path[i]], 
              [interpolate(path,len(path),i)],
              subdivide(path, i+1))
     : [];
function smooth(path,n) =
    n == 0
     ?  path
     :  smooth(subdivide(path),n-1);
function path_segment(path,start,end) =
    let (l = len(path))
    let (s = max(floor(start * 360 / l),0),
         e = min(ceil(end * 360 / l),l - 1))
    [for (i=[s:e]) path[i]];
function scale(path,scale,i=0) =
    [for (p =path)
       [p[0]*scale[0],p[1]*scale[1],p[2]*scale[2]]
    ];
function curve_length(step,t=0) =
    t < 360
      ?  norm(f(t+step) - f(t)) + curve_length(step,t+step)
      :  0;
function map(t, min, max) =
      min + t* (max-min)/360;
      
      
function limit_point(p,l) = [p.x,p.y,p.z < l ? l : p.z];
    
function limit_points(points,l) =
   [for (p = points) limit_point(p,l)];
    
//  create a knot from a path 
function path_knot(path,r,sides,kscale,phase=45,base=-10000,open=false)  =
  let(loop_points = scale(path,kscale))
  let(circle_points = circle_points(r,sides,phase))
  let(tube_points = tube_points(loop_points,circle_points))
  let(base_tube_points = limit_points(tube_points,base))
  let(loop_faces = loop_faces(len(loop_points),sides,open))
  poly(name="Knot",
         vertices = base_tube_points,
         faces = loop_faces);