diff --git a/beziers.scad b/beziers.scad index 31fc031..ad73928 100644 --- a/beziers.scad +++ b/beziers.scad @@ -331,36 +331,40 @@ function bezier_polyline(bezier, splinesteps=16, N=3) = let( // Usage: // path_to_bezier(path,[tangent],[k],[closed]); // Description: -// Given an input path and optional path of tangent vectors, computes a cubic (degree 3) bezier path that passes -// through every point on the input path and matches the tangent vectors. If you do not supply -// the tangent it will be computed using path_tangents. If the path is closed specify this +// Given an input path and optional path of tangent vectors, computes a cubic (degree 3) bezier path +// that passes through every point on the input path and matches the tangent vectors. If you do not +// supply the tangent it will be computed using path_tangents. If the path is closed specify this // by setting closed=true. If you specify the curvature parameter k it scales the tangent vectors, -// which will increase or decrease the curvature of the interpolated bezier. Negative values of k create loops at the corners, -// so they are not allowed. Sufficiently large k values will also produce loops. +// which will increase or decrease the curvature of the interpolated bezier. Negative values of k +// create loops at the corners, so they are not allowed. Sufficiently large k values will also +// produce loops. // Arguments: // path = path of points to define the bezier // tangents = optional list of tangent vectors at every point // k = curvature parameter, a scalar or vector to adjust curvature at each point // closed = set to true for a closed path. Default: false function path_to_bezier(path, tangents, k, closed=false) = - assert(is_path(path,dim=undef),"Input path is not a valid path") - assert(is_undef(tangents) || is_path(tangents,dim=len(path[0])),"Tangents must be a path of the same dimension as the input path") - assert(is_undef(tangents) || len(path)==len(tangents), "Input tangents must be the same length as the input path") - let( - k = is_undef(k) ? repeat(1, len(path)) : - is_list(k) ? k : repeat(k, len(path)), - k_bad = [for(entry=k) if (entry<0) entry] - ) - assert(len(k)==len(path), "Curvature parameter k must have the same length as the path") - assert(k_bad==[], "Curvature parameter k must be a nonnegative number or list of nonnegative numbers") - let( - tangents = is_def(tangents)? tangents : deriv(path, closed=closed), - lastpt = len(path) - (closed?0:1) - ) - [for(i=[0:lastpt-1]) each [path[i], - path[i]+k[i]*tangents[i]/3, - select(path,i+1)-select(k,i+1)*select(tangents,i+1)/3], - select(path,lastpt)]; + assert(is_path(path,dim=undef),"Input path is not a valid path") + assert(is_undef(tangents) || is_path(tangents,dim=len(path[0])),"Tangents must be a path of the same dimension as the input path") + assert(is_undef(tangents) || len(path)==len(tangents), "Input tangents must be the same length as the input path") + let( + k = is_undef(k) ? repeat(1, len(path)) : + is_list(k) ? k : repeat(k, len(path)), + k_bad = [for(entry=k) if (entry<0) entry] + ) + assert(len(k)==len(path), "Curvature parameter k must have the same length as the path") + assert(k_bad==[], "Curvature parameter k must be a nonnegative number or list of nonnegative numbers") + let( + tangents = is_def(tangents)? tangents : deriv(path, closed=closed), + lastpt = len(path) - (closed?0:1) + ) [ + for(i=[0:lastpt-1]) each [ + path[i], + path[i]+k[i]*tangents[i]/3, + select(path,i+1)-select(k,i+1)*select(tangents,i+1)/3 + ], + select(path,lastpt) + ]; // Function: fillet_path() @@ -827,7 +831,7 @@ function bezier_patch(patch, splinesteps=16, vnf=EMPTY_VNF, style="default") = ] ], vnf = vnf_vertex_array(pts, style=style, vnf=vnf) - ) vnf; + ) vnf; function _tri_count(n) = (n*(1+n))/2; @@ -977,14 +981,18 @@ module bezier_polyhedron(patches=[], splinesteps=16, vnf=EMPTY_VNF, style="defau // Module: trace_bezier_patches() // Usage: -// trace_bezier_patches(patches, [size], [showcps], [splinesteps]); +// trace_bezier_patches(patches, [size], [splinesteps], [showcps], [showdots], [showpatch], [convexity], [style]); // Description: // Shows the surface, and optionally, control points of a list of bezier patches. // Arguments: // patches = A list of rectangular bezier patches. // splinesteps = Number of steps to divide each bezier segment into. default=16 -// showcps = If true, show the controlpoints as well as the surface. +// showcps = If true, show the controlpoints as well as the surface. Default: true. +// showdots = If true, shows the calculated surface vertices. Default: false. +// showpatch = If true, shows the surface faces. Default: true. // size = Size to show control points and lines. +// style = The style of subdividing the quads into faces. Valid options are "default", "alt", and "quincunx". +// convexity = Max number of times a line could intersect a wall of the shape. // Example: // patch1 = [ // [[15,15,0], [33, 0, 0], [ 67, 0, 0], [ 85, 15,0]], @@ -999,32 +1007,39 @@ module bezier_polyhedron(patches=[], splinesteps=16, vnf=EMPTY_VNF, style="defau // [[15,85,0], [33,100, 0], [ 67,100, 0], [ 85, 85,0]], // ]; // trace_bezier_patches(patches=[patch1, patch2], splinesteps=8, showcps=true); -module trace_bezier_patches(patches=[], size=1, showcps=false, splinesteps=16, showpatch=true, showdots=true) +module trace_bezier_patches(patches=[], size, splinesteps=16, showcps=true, showdots=false, showpatch=true, convexity=10, style="default") { - if (showcps) { + if (showcps || showdots) { for (patch = patches) { - move_copies(flatten(patch)) color("red") sphere(d=size*2); - color("cyan") - if (is_tripatch(patch)) { - for (i=[0:1:len(patch)-2], j=[0:1:len(patch[i])-2]) { - extrude_from_to(patch[i][j], patch[i+1][j]) circle(d=size); - extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size); - extrude_from_to(patch[i+1][j], patch[i][j+1]) circle(d=size); - } - } else { - for (i=[0:1:len(patch)-1], j=[0:1:len(patch[i])-1]) { - if (i