diff --git a/arrays.scad b/arrays.scad index be3bd7c..74d2ea90 100644 --- a/arrays.scad +++ b/arrays.scad @@ -424,8 +424,9 @@ function repeat(val, n, i=0) = // list = count(n, [s], [step], [reverse]); // Description: // Creates a list of `n` numbers, starting at `s`, incrementing by `step` each time. +// You can also pass a list for n and then the length of the input list is used. // Arguments: -// n = The length of the list of numbers to create. +// n = The length of the list of numbers to create, or a list to match the length of // s = The starting value of the list of numbers. // step = The amount to increment successive numbers in the list. // reverse = Reverse the list. Default: false. @@ -435,7 +436,8 @@ function repeat(val, n, i=0) = // nl3 = count(4,3,2); // Returns: [3,5,7,9] // nl4 = count(5,reverse=true); // Returns: [4,3,2,1,0] // nl5 = count(5,3,reverse=true); // Returns: [7,6,5,4,3] -function count(n,s=0,step=1,reverse=false) = reverse? [for (i=[n-1:-1:0]) s+i*step] +function count(n,s=0,step=1,reverse=false) = let(n=is_list(n) ? len(n) : n) + reverse? [for (i=[n-1:-1:0]) s+i*step] : [for (i=[0:1:n-1]) s+i*step]; diff --git a/paths.scad b/paths.scad index 40159bc..74451c8 100644 --- a/paths.scad +++ b/paths.scad @@ -441,7 +441,7 @@ function resample_path(path, N, spacing, closed=false) = // Usage: // bool = is_path_simple(path, [closed], [eps]); // Description: -// Returns true if the path is simple, meaning that it has no self-intersections. +// Returns true if the given 2D path is simple, meaning that it has no self-intersections. // Repeated points are not considered self-intersections: a path with such points can // still be simple. // If closed is set to true then treat the path as a polygon. @@ -450,6 +450,7 @@ function resample_path(path, N, spacing, closed=false) = // closed = set to true to treat path as a polygon. Default: false // eps = Epsilon error value used for determine if points coincide. Default: `EPSILON` (1e-9) function is_path_simple(path, closed=false, eps=EPSILON) = + assert(is_path(path, 2),"Must give a 2D path") [for(i=[0:1:len(path)-(closed?2:3)]) let(v1=path[i+1]-path[i], v2=select(path,i+2)-path[i+1], diff --git a/regions.scad b/regions.scad index 3f0a4c5..6777abb 100644 --- a/regions.scad +++ b/regions.scad @@ -688,10 +688,11 @@ function _point_dist(path,pathseg_unit,pathseg_len,pt) = // offsetpath = offset(path, [r|delta], [chamfer], [closed], [check_valid], [quality]) // path_faces = offset(path, return_faces=true, [r|delta], [chamfer], [closed], [check_valid], [quality], [firstface_index], [flip_faces]) // Description: -// Takes an input path and returns a path offset by the specified amount. As with the built-in +// Takes a 2D input path and returns a path offset by the specified amount. As with the built-in // offset() module, you can use `r` to specify rounded offset and `delta` to specify offset with // corners. If you used `delta` you can set `chamfer` to true to get chamfers. -// Positive offsets shift the path to the left (relative to the direction of the path). +// Positive offsets shift the path to the left (relative to the direction of the path). Note +// that the path must not include any 180 degree turns, where the path reverses direction. // . // When offsets shrink the path, segments cross and become invalid. By default `offset()` checks // for this situation. To test validity the code checks that segments have distance larger than (r @@ -831,7 +832,7 @@ function offset( (len(sharpcorners)==2 && !closed) || all_defined(closed? sharpcorners : select(sharpcorners, 1,-2)) ) - assert(parallelcheck, "Path contains sequential parallel segments (either 180 deg turn or 0 deg turn") + assert(parallelcheck, "Path contains a segment that reverses direction (180 deg turn)") let( // This is a boolean array that indicates whether a corner is an outside or inside corner // For outside corners, the newcorner is an extension (angle 0), for inside corners, it turns backward diff --git a/rounding.scad b/rounding.scad index 425db47..3fca7d5 100644 --- a/rounding.scad +++ b/rounding.scad @@ -1954,7 +1954,7 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b assert(debug || bot_simple, "Roundovers interfere with each other on bottom face: either input is self intersecting or top joint length is too large") assert(debug || (verify_vert==[] && verify_horiz==[]), "Curvature continuity failed") - let( + let( vnf = vnf_merge([ each subindex(top_samples,0), each subindex(bot_samples,0), for(pts=edge_points) vnf_vertex_array(pts), diff --git a/vnf.scad b/vnf.scad index 1534f5c..24fc232 100644 --- a/vnf.scad +++ b/vnf.scad @@ -587,7 +587,9 @@ module vnf_wireframe(vnf, width=1) sort([face[i], select(face,i+1)]) ]); for (e=edges) extrude_from_to(vertex[e[0]],vertex[e[1]]) circle(d=width); - move_copies(vertex) sphere(d=width); + // Identify vertices actually used and draw them + vertused = search(count(len(vertex)), flatten(edges), 1); + for(i=idx(vertex)) if(vertused[i]!=[]) move(vertex[i]) sphere(d=width); } @@ -687,6 +689,8 @@ function vnf_centroid(vnf) = // cut_knot = vnf_halfspace([1,0,0,0], knot); // vnf_polyhedron(cut_knot); function vnf_halfspace(plane, vnf, closed=true) = + assert(_valid_plane(plane), "Invalid plane") + assert(is_vnf(vnf), "Invalid vnf") let( inside = [for(x=vnf[0]) plane*[each x,-1] >= 0 ? 1 : 0], vertexmap = [0,each cumsum(inside)],