From 9ca77eed1beb284fc01473a11dff6795458ff39c Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 18 Sep 2021 19:11:08 -0400 Subject: [PATCH] path.scad cleanup (hid/removed several functions) --- attachments.scad | 2 +- debug.scad | 4 +- drawing.scad | 12 +- paths.scad | 348 +++++++++++++++--------------------------- regions.scad | 4 +- shapes3d.scad | 6 +- skin.scad | 4 +- tests/test_paths.scad | 12 +- wiring.scad | 2 +- 9 files changed, 137 insertions(+), 257 deletions(-) diff --git a/attachments.scad b/attachments.scad index 3dece51..a16b40b 100644 --- a/attachments.scad +++ b/attachments.scad @@ -13,7 +13,7 @@ // Default values for attachment code. $tags = ""; $overlap = 0; -$color = "yellow"; +$color = undef;//"yellow"; $attach_to = undef; $attach_anchor = [CENTER, CENTER, UP, 0]; diff --git a/debug.scad b/debug.scad index 2289cb6..5d02c7e 100644 --- a/debug.scad +++ b/debug.scad @@ -346,7 +346,9 @@ module expose_anchors(opacity=0.2) { show("anchor-arrow") children(); hide("anchor-arrow") - color(is_string($color)? $color : point3d($color), opacity) + color(is_undef($color)? [0,0,0] : + is_string($color)? $color : + point3d($color), opacity) children(); } diff --git a/drawing.scad b/drawing.scad index 8064ebc..89d31a5 100644 --- a/drawing.scad +++ b/drawing.scad @@ -251,14 +251,10 @@ module stroke( translate(path[0]) sphere(d=width[0]); } } else { - spos = path_pos_from_start(path,trim1,closed=false); - epos = path_pos_from_end(path,trim2,closed=false); - path2 = path_subselect(path, spos[0], spos[1], epos[0], epos[1]); - widths = concat( - [lerp(width[spos[0]], width[(spos[0]+1)%len(width)], spos[1])], - [for (i = [spos[0]+1:1:epos[0]]) width[i]], - [lerp(width[epos[0]], width[(epos[0]+1)%len(width)], epos[1])] - ); + pathcut = path_cut_points(path, [trim1, path_length(path)-trim2], closed=false); + pathcut_su = _cut_to_seg_u_form(pathcut,path); + path2 = _path_cut_getpaths(path, pathcut, closed=false)[1]; + widths = _path_select(width, pathcut_su[0][0], pathcut_su[0][1], pathcut_su[1][0], pathcut_su[1][1]); start_vec = path[0] - path[1]; end_vec = last(path) - select(path,-2); diff --git a/paths.scad b/paths.scad index 53f78fb..d337913 100644 --- a/paths.scad +++ b/paths.scad @@ -72,21 +72,21 @@ function cleanup_path(path, eps=EPSILON) = is_closed_path(path,eps=eps)? [for (i=[0:1:len(path)-2]) path[i]] : path; -// Function: path_subselect() -// Usage: -// path_subselect(path,s1,u1,s2,u2,[closed]): -// Description: -// Returns a portion of a path, from between the `u1` part of segment `s1`, to the `u2` part of -// segment `s2`. Both `u1` and `u2` are values between 0.0 and 1.0, inclusive, where 0 is the start -// of the segment, and 1 is the end. Both `s1` and `s2` are integers, where 0 is the first segment. -// Arguments: -// path = The path to get a section of. -// s1 = The number of the starting segment. -// u1 = The proportion along the starting segment, between 0.0 and 1.0, inclusive. -// s2 = The number of the ending segment. -// u2 = The proportion along the ending segment, between 0.0 and 1.0, inclusive. -// closed = If true, treat path as a closed polygon. -function path_subselect(path, s1, u1, s2, u2, closed=false) = +/// internal Function: _path_select() +/// Usage: +/// _path_select(path,s1,u1,s2,u2,[closed]): +/// Description: +/// Returns a portion of a path, from between the `u1` part of segment `s1`, to the `u2` part of +/// segment `s2`. Both `u1` and `u2` are values between 0.0 and 1.0, inclusive, where 0 is the start +/// of the segment, and 1 is the end. Both `s1` and `s2` are integers, where 0 is the first segment. +/// Arguments: +/// path = The path to get a section of. +/// s1 = The number of the starting segment. +/// u1 = The proportion along the starting segment, between 0.0 and 1.0, inclusive. +/// s2 = The number of the ending segment. +/// u2 = The proportion along the ending segment, between 0.0 and 1.0, inclusive. +/// closed = If true, treat path as a closed polygon. +function _path_select(path, s1, u1, s2, u2, closed=false) = let( lp = len(path), l = lp-(closed?0:1), @@ -102,15 +102,15 @@ function path_subselect(path, s1, u1, s2, u2, closed=false) = ) pathout; -// Function: simplify_path() +// Function: path_merge_collinear() // Description: -// Takes a path and removes unnecessary subsequent collinear points. +// Takes a path and removes unnecessary sequential collinear points. // Usage: -// simplify_path(path, [eps]) +// path_merge_collinear(path, [eps]) // Arguments: // path = A list of path points of any dimension. // eps = Largest positional variance allowed. Default: `EPSILON` (1-e9) -function simplify_path(path, eps=EPSILON) = +function path_merge_collinear(path, eps=EPSILON) = assert( is_path(path), "Invalid path." ) assert( is_undef(eps) || (is_finite(eps) && (eps>=0) ), "Invalid tolerance." ) len(path)<=2 ? path : @@ -124,34 +124,6 @@ function simplify_path(path, eps=EPSILON) = ) [for (i=indices) path[i]]; -// Function: simplify_path_indexed() -// Description: -// Takes a list of points, and a list of indices into `points`, -// and removes from the list all indices of subsequent indexed points that are unecessarily collinear. -// Returns the list of the remained indices. -// Usage: -// simplify_path_indexed(points,indices, eps) -// Arguments: -// points = A list of points. -// indices = A list of indices into `points` that forms a path. -// eps = Largest angle variance allowed. Default: EPSILON (1-e9) degrees. -function simplify_path_indexed(points, indices, eps=EPSILON) = - len(indices)<=2? indices : - let( - indices = concat( - indices[0], - [ - for (i=[1:1:len(indices)-2]) let( - i1 = indices[i-1], - i2 = indices[i], - i3 = indices[i+1] - ) if (!is_collinear(points[i1], points[i2], points[i3], eps=eps)) - indices[i] - ], - indices[len(indices)-1] - ) - ) indices; - // Function: path_length() // Usage: @@ -184,111 +156,6 @@ function path_segment_lengths(path, closed=false) = ]; -// Function: path_pos_from_start() -// Usage: -// pos = path_pos_from_start(path,length,[closed]); -// Description: -// Finds the segment and relative position along that segment that is `length` distance from the -// front of the given `path`. Returned as [SEGNUM, U] where SEGNUM is the segment number, and U is -// the relative distance along that segment, a number from 0 to 1. If the path is shorter than the -// asked for length, this returns `undef`. -// Arguments: -// path = The path to find the position on. -// length = The length from the start of the path to find the segment and position of. -// Example(2D): -// path = circle(d=50,$fn=18); -// pos = path_pos_from_start(path,20,closed=false); -// stroke(path,width=1,endcaps=false); -// pt = lerp(path[pos[0]], path[(pos[0]+1)%len(path)], pos[1]); -// color("red") translate(pt) circle(d=2,$fn=12); -function path_pos_from_start(path,length,closed=false,_d=0,_i=0) = - let (lp = len(path)) - _i >= lp - (closed?0:1)? undef : - let (l = norm(path[(_i+1)%lp]-path[_i])) - _d+l <= length? path_pos_from_start(path,length,closed,_d+l,_i+1) : - [_i, (length-_d)/l]; - - -// Function: path_pos_from_end() -// Usage: -// pos = path_pos_from_end(path,length,[closed]); -// Description: -// Finds the segment and relative position along that segment that is `length` distance from the -// end of the given `path`. Returned as [SEGNUM, U] where SEGNUM is the segment number, and U is -// the relative distance along that segment, a number from 0 to 1. If the path is shorter than the -// asked for length, this returns `undef`. -// Arguments: -// path = The path to find the position on. -// length = The length from the end of the path to find the segment and position of. -// Example(2D): -// path = circle(d=50,$fn=18); -// pos = path_pos_from_end(path,20,closed=false); -// stroke(path,width=1,endcaps=false); -// pt = lerp(path[pos[0]], path[(pos[0]+1)%len(path)], pos[1]); -// color("red") translate(pt) circle(d=2,$fn=12); -function path_pos_from_end(path,length,closed=false,_d=0,_i=undef) = - let ( - lp = len(path), - _i = _i!=undef? _i : lp - (closed?1:2) - ) - _i < 0? undef : - let (l = norm(path[(_i+1)%lp]-path[_i])) - _d+l <= length? path_pos_from_end(path,length,closed,_d+l,_i-1) : - [_i, 1-(length-_d)/l]; - - -// Function: path_trim_start() -// Usage: -// path_trim_start(path,trim); -// Description: -// Returns the `path`, with the start shortened by the length `trim`. -// Arguments: -// path = The path to trim. -// trim = The length to trim from the start. -// Example(2D): -// path = circle(d=50,$fn=18); -// path2 = path_trim_start(path,5); -// path3 = path_trim_start(path,20); -// color("blue") stroke(path3,width=5,endcaps=false); -// color("cyan") stroke(path2,width=3,endcaps=false); -// color("red") stroke(path,width=1,endcaps=false); -function path_trim_start(path,trim,_d=0,_i=0) = - _i >= len(path)-1? [] : - let (l = norm(path[_i+1]-path[_i])) - _d+l <= trim? path_trim_start(path,trim,_d+l,_i+1) : - let (v = unit(path[_i+1]-path[_i])) - concat( - [path[_i+1]-v*(l-(trim-_d))], - [for (i=[_i+1:1:len(path)-1]) path[i]] - ); - - -// Function: path_trim_end() -// Usage: -// path_trim_end(path,trim); -// Description: -// Returns the `path`, with the end shortened by the length `trim`. -// Arguments: -// path = The path to trim. -// trim = The length to trim from the end. -// Example(2D): -// path = circle(d=50,$fn=18); -// path2 = path_trim_end(path,5); -// path3 = path_trim_end(path,20); -// color("blue") stroke(path3,width=5,endcaps=false); -// color("cyan") stroke(path2,width=3,endcaps=false); -// color("red") stroke(path,width=1,endcaps=false); -function path_trim_end(path,trim,_d=0,_i=undef) = - let (_i = _i!=undef? _i : len(path)-1) - _i <= 0? [] : - let (l = norm(path[_i]-path[_i-1])) - _d+l <= trim? path_trim_end(path,trim,_d+l,_i-1) : - let (v = unit(path[_i]-path[_i-1])) - concat( - [for (i=[0:1:_i-1]) path[i]], - [path[_i-1]+v*(l-(trim-_d))] - ); - // Function: path_closest_point() // Usage: @@ -700,7 +567,7 @@ function split_path_at_self_crossings(path, closed=true, eps=EPSILON) = u1 = p[0][1], s2 = p[1][0], u2 = p[1][1], - section = path_subselect(path, s1, u1, s2, u2, closed=closed), + section = _path_select(path, s1, u1, s2, u2, closed=closed), outpath = deduplicate(eps=eps, section) ) outpath @@ -747,7 +614,7 @@ function decompose_path(path, closed=true, eps=EPSILON) = path = cleanup_path(path, eps=eps), tagged = _tag_self_crossing_subpaths(path, closed=closed, eps=eps), kept = [for (sub = tagged) if(sub[0] == "O") sub[1]], - outregion = assemble_path_fragments(kept, eps=eps) + outregion = _assemble_path_fragments(kept, eps=eps) ) outregion; @@ -784,19 +651,19 @@ function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) = ) [foundfrag, remainder]; -// Function: assemble_a_path_from_fragments() -// Usage: -// assemble_a_path_from_fragments(subpaths); -// Description: -// Given a list of paths, assembles them together into one complete closed polygon path, and -// remainder fragments. Returns [PATH, FRAGMENTS] where FRAGMENTS is the list of remaining -// unused path fragments. -// Arguments: -// fragments = List of paths to be assembled into complete polygons. -// rightmost = If true, assemble paths using rightmost turns. Leftmost if false. -// startfrag = The fragment to start with. Default: 0 -// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9) -function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, eps=EPSILON) = +/// Internal Function: _assemble_a_path_from_fragments() +/// Usage: +/// _assemble_a_path_from_fragments(subpaths); +/// Description: +/// Given a list of paths, assembles them together into one complete closed polygon path, and +/// remainder fragments. Returns [PATH, FRAGMENTS] where FRAGMENTS is the list of remaining +/// unused path fragments. +/// Arguments: +/// fragments = List of paths to be assembled into complete polygons. +/// rightmost = If true, assemble paths using rightmost turns. Leftmost if false. +/// startfrag = The fragment to start with. Default: 0 +/// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9) +function _assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, eps=EPSILON) = len(fragments)==0? _finished : let( path = fragments[startfrag], @@ -834,34 +701,34 @@ function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, newpath = concat(path, list_tail(foundfrag)), newfrags = concat([newpath], remainder) ) - assemble_a_path_from_fragments( + _assemble_a_path_from_fragments( fragments=newfrags, rightmost=rightmost, eps=eps ); -// Function: assemble_path_fragments() -// Usage: -// assemble_path_fragments(subpaths); -// Description: -// Given a list of paths, assembles them together into complete closed polygon paths if it can. -// Arguments: -// fragments = List of paths to be assembled into complete polygons. -// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9) -function assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) = +/// Internal Function: _assemble_path_fragments() +/// Usage: +/// _assemble_path_fragments(subpaths); +/// Description: +/// Given a list of paths, assembles them together into complete closed polygon paths if it can. +/// Arguments: +/// fragments = List of paths to be assembled into complete polygons. +/// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9) +function _assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) = len(fragments)==0? _finished : let( minxidx = min_index([ for (frag=fragments) min(subindex(frag,0)) ]), - result_l = assemble_a_path_from_fragments( + result_l = _assemble_a_path_from_fragments( fragments=fragments, startfrag=minxidx, rightmost=false, eps=eps ), - result_r = assemble_a_path_from_fragments( + result_r = _assemble_a_path_from_fragments( fragments=fragments, startfrag=minxidx, rightmost=true, @@ -873,7 +740,7 @@ function assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) = newpath = cleanup_path(result[0]), remainder = result[1], finished = concat(_finished, [newpath]) - ) assemble_path_fragments( + ) _assemble_path_fragments( fragments=remainder, eps=eps, _finished=finished @@ -881,47 +748,47 @@ function assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) = -// Function: path_cut_points() -// -// Usage: -// cuts = path_cut_points(path, dists, [closed=], [direction=]); -// -// Description: -// Cuts a path at a list of distances from the first point in the path. Returns a list of the cut -// points and indices of the next point in the path after that point. So for example, a return -// value entry of [[2,3], 5] means that the cut point was [2,3] and the next point on the path after -// this point is path[5]. If the path is too short then path_cut_points returns undef. If you set -// `direction` to true then `path_cut_points` will also return the tangent vector to the path and a normal -// vector to the path. It tries to find a normal vector that is coplanar to the path near the cut -// point. If this fails it will return a normal vector parallel to the xy plane. The output with -// direction vectors will be `[point, next_index, tangent, normal]`. -// . -// If you give the very last point of the path as a cut point then the returned index will be -// one larger than the last index (so it will not be a valid index). If you use the closed -// option then the returned index will be equal to the path length for cuts along the closing -// path segment, and if you give a point equal to the path length you will get an -// index of len(path)+1 for the index. -// -// Arguments: -// path = path to cut -// dists = distances where the path should be cut (a list) or a scalar single distance -// --- -// closed = set to true if the curve is closed. Default: false -// direction = set to true to return direction vectors. Default: false -// -// Example(NORENDER): -// square=[[0,0],[1,0],[1,1],[0,1]]; -// path_cut_points(square, [.5,1.5,2.5]); // Returns [[[0.5, 0], 1], [[1, 0.5], 2], [[0.5, 1], 3]] -// path_cut_points(square, [0,1,2,3]); // Returns [[[0, 0], 1], [[1, 0], 2], [[1, 1], 3], [[0, 1], 4]] -// path_cut_points(square, [0,0.8,1.6,2.4,3.2], closed=true); // Returns [[[0, 0], 1], [[0.8, 0], 1], [[1, 0.6], 2], [[0.6, 1], 3], [[0, 0.8], 4]] -// path_cut_points(square, [0,0.8,1.6,2.4,3.2]); // Returns [[[0, 0], 1], [[0.8, 0], 1], [[1, 0.6], 2], [[0.6, 1], 3], undef] -function path_cut_points(path, dists, closed=false, direction=false) = +/// Internal Function: _path_cut_points() +/// +/// Usage: +/// cuts = _path_cut_points(path, dists, [closed=], [direction=]); +/// +/// Description: +/// Cuts a path at a list of distances from the first point in the path. Returns a list of the cut +/// points and indices of the next point in the path after that point. So for example, a return +/// value entry of [[2,3], 5] means that the cut point was [2,3] and the next point on the path after +/// this point is path[5]. If the path is too short then path_cut_points returns undef. If you set +/// `direction` to true then `path_cut_points` will also return the tangent vector to the path and a normal +/// vector to the path. It tries to find a normal vector that is coplanar to the path near the cut +/// point. If this fails it will return a normal vector parallel to the xy plane. The output with +/// direction vectors will be `[point, next_index, tangent, normal]`. +/// . +/// If you give the very last point of the path as a cut point then the returned index will be +/// one larger than the last index (so it will not be a valid index). If you use the closed +/// option then the returned index will be equal to the path length for cuts along the closing +/// path segment, and if you give a point equal to the path length you will get an +/// index of len(path)+1 for the index. +/// +/// Arguments: +/// path = path to cut +/// dists = distances where the path should be cut (a list) or a scalar single distance +/// --- +/// closed = set to true if the curve is closed. Default: false +/// direction = set to true to return direction vectors. Default: false +/// +/// Example(NORENDER): +/// square=[[0,0],[1,0],[1,1],[0,1]]; +/// _path_cut_points(square, [.5,1.5,2.5]); // Returns [[[0.5, 0], 1], [[1, 0.5], 2], [[0.5, 1], 3]] +/// _path_cut_points(square, [0,1,2,3]); // Returns [[[0, 0], 1], [[1, 0], 2], [[1, 1], 3], [[0, 1], 4]] +/// _path_cut_points(square, [0,0.8,1.6,2.4,3.2], closed=true); // Returns [[[0, 0], 1], [[0.8, 0], 1], [[1, 0.6], 2], [[0.6, 1], 3], [[0, 0.8], 4]] +/// _path_cut_points(square, [0,0.8,1.6,2.4,3.2]); // Returns [[[0, 0], 1], [[0.8, 0], 1], [[1, 0.6], 2], [[0.6, 1], 3], undef] +function _path_cut_points(path, dists, closed=false, direction=false) = let(long_enough = len(path) >= (closed ? 3 : 2)) assert(long_enough,len(path)<2 ? "Two points needed to define a path" : "Closed path must include three points") - is_num(dists) ? path_cut_points(path, [dists],closed, direction)[0] : + is_num(dists) ? _path_cut_points(path, [dists],closed, direction)[0] : assert(is_vector(dists)) assert(list_increasing(dists), "Cut distances must be an increasing list") - let(cuts = _path_cut_points(path,dists,closed)) + let(cuts = _path_cut_points_recurse(path,dists,closed)) !direction ? cuts : let( @@ -931,7 +798,7 @@ function path_cut_points(path, dists, closed=false, direction=false) = hstack(cuts, array_group(dir,1), array_group(normals,1)); // Main recursive path cut function -function _path_cut_points(path, dists, closed=false, pind=0, dtotal=0, dind=0, result=[]) = +function _path_cut_points_recurse(path, dists, closed=false, pind=0, dtotal=0, dind=0, result=[]) = dind == len(dists) ? result : let( lastpt = len(result)==0? [] : last(result)[0], // location of last cut point @@ -940,7 +807,7 @@ function _path_cut_points(path, dists, closed=false, pind=0, dtotal=0, dind=0, r ? [lerp(lastpt,select(path,pind),(dists[dind]-dtotal)/dpartial),pind] : _path_cut_single(path, dists[dind]-dtotal-dpartial, closed, pind) ) - _path_cut_points(path, dists, closed, nextpoint[1], dists[dind],dind+1, concat(result, [nextpoint])); + _path_cut_points_recurse(path, dists, closed, nextpoint[1], dists[dind],dind+1, concat(result, [nextpoint])); // Search for a single cut point in the path @@ -1000,7 +867,7 @@ function _path_cuts_dir(path, cuts, closed=false, eps=1e-2) = // Function: path_cut() // Topics: Paths -// See Also: path_cut_points() +// See Also: _path_cut_points() // Usage: // path_list = path_cut(path, cutdist, [closed=]); // Description: @@ -1008,8 +875,11 @@ function _path_cuts_dir(path, cuts, closed=false, eps=1e-2) = // subpaths at those lengths, returning a list of paths. // If the input path is closed then the final path will include the // original starting point. The list of cut distances must be -// in ascending order. If you repeat a distance you will get an -// empty list in that position in the output. +// in ascending order and should not include the endpoints: 0 +// or len(path). If you repeat a distance you will get an +// empty list in that position in the output. If you give an +// empty cutdist array you will get the input path as output +// (without the final vertex doubled in the case of a closed path). // Arguments: // path = The original path to split. // cutdist = Distance or list of distances where path is cut @@ -1021,14 +891,16 @@ function _path_cuts_dir(path, cuts, closed=false, eps=1e-2) = function path_cut(path,cutdist,closed) = is_num(cutdist) ? path_cut(path,[cutdist],closed) : assert(is_vector(cutdist)) - - assert(last(cutdist)0, "Cut distances must be strictly positive") let( - cutlist = path_cut_points(path,cutdist,closed=closed), + cutlist = _path_cut_points(path,cutdist,closed=closed) + ) + _path_cut_getpaths(path, cutlist, closed); + + +function _path_cut_getpaths(path, cutlist, closed) = + let( cuts = len(cutlist) ) [ @@ -1049,6 +921,24 @@ function path_cut(path,cutdist,closed) = ]; +// internal function +// converts pathcut output form to a [segment, u] +// form list that works withi path_select +function _cut_to_seg_u_form(pathcut, path, closed) = + let(lastind = len(path) - (closed?0:1)) + [for(entry=pathcut) + entry[1] > lastind ? [lastind,0] : + let( + a = path[entry[1]-1], + b = path[entry[1]], + c = entry[0], + i = max_index(v_abs(b-a)), + factor = (c[i]-a[i])/(b[i]-a[i]) + ) + [entry[1]-1,factor] + ]; + + // Input `data` is a list that sums to an integer. // Returns rounded version of input data so that every @@ -1212,7 +1102,7 @@ function resample_path(path, N, spacing, closed=false) = // Add last point later N = is_def(N) ? N-(closed?0:1) : round(length/spacing), distlist = lerpn(0,length,N,false), - cuts = path_cut_points(path, distlist, closed=closed) + cuts = _path_cut_points(path, distlist, closed=closed) ) [ each subindex(cuts,0), if (!closed) last(path) // Then add last point here diff --git a/regions.scad b/regions.scad index 258b958..c7d771d 100644 --- a/regions.scad +++ b/regions.scad @@ -248,7 +248,7 @@ function split_path_at_region_crossings(path, region, closed=true, eps=EPSILON) subpaths = [ for (p = pair(crossings)) deduplicate( - path_subselect(path, p[0][0], p[0][1], p[1][0], p[1][1], closed=closed), + _path_select(path, p[0][0], p[0][1], p[1][0], p[1][1], closed=closed), eps=eps ) ] @@ -861,7 +861,7 @@ function _tagged_region(region1,region2,keep1,keep2,eps=EPSILON) = [for (tagpath = tagged1) if (in_list(tagpath[0], keep1)) tagpath[1]], [for (tagpath = tagged2) if (in_list(tagpath[0], keep2)) tagpath[1]] ), - outregion = assemble_path_fragments(tagged, eps=eps) + outregion = _assemble_path_fragments(tagged, eps=eps) ) outregion; diff --git a/shapes3d.scad b/shapes3d.scad index 23d6aab..76f5647 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2004,10 +2004,7 @@ module atext(text, h=1, size=9, font="Courier", anchor="baseline", spin=0, orien } } - - - - +// This could be replaced with _cut_to_seg_u_form function _cut_interp(pathcut, path, data) = [for(entry=pathcut) let( @@ -2021,6 +2018,7 @@ function _cut_interp(pathcut, path, data) = ]; + // Module: path_text() // Usage: // path_text(path, text, [size], [thickness], [font], [lettersize], [offset], [reverse], [normal], [top], [textmetrics]) diff --git a/skin.scad b/skin.scad index 5e39c89..4640086 100644 --- a/skin.scad +++ b/skin.scad @@ -694,14 +694,14 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close // Example: The "natural" method will introduce twists when the curvature changes direction. A warning is displayed. // arc1 = path3d(arc(angle=90, r=30)); // arc2 = xrot(-90, cp=[0,30],p=path3d(arc(angle=[90,180], r=30))); -// two_arcs = simplify_path(concat(arc1,arc2)); +// two_arcs = path_merge_collinear(concat(arc1,arc2)); // ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]]; // path_sweep(ushape, two_arcs, method="natural"); // Example: The only simple way to get a good result is the "incremental" method: // arc1 = path3d(arc(angle=90, r=30)); // arc2 = xrot(-90, cp=[0,30],p=path3d(arc(angle=[90,180], r=30))); // arc3 = apply( translate([-30,60,30])*yrot(90), path3d(arc(angle=[270,180], r=30))); -// three_arcs = simplify_path(concat(arc1,arc2,arc3)); +// three_arcs = path_merge_collinear(concat(arc1,arc2,arc3)); // ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]]; // path_sweep(ushape, three_arcs, method="incremental"); // Example: knot example from list-comprehension-demos, "incremental" method diff --git a/tests/test_paths.scad b/tests/test_paths.scad index 76950c2..63a635a 100644 --- a/tests/test_paths.scad +++ b/tests/test_paths.scad @@ -36,16 +36,10 @@ module test_cleanup_path() { test_cleanup_path(); -module test_simplify_path() { +module test_path_merge_collinear() { path = [[-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]]; - assert(simplify_path(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]); + assert(path_merge_collinear(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]); } -test_simplify_path(); +test_path_merge_collinear(); -module test_simplify_path_indexed() { - pts = [[10,0], [0,-10], [20,20], [20,10], [-20,-20], [15,30], [-10,-20]]; - path = [4,6,1,0,3,2,5]; - assert(simplify_path_indexed(pts, path) == [4,6,3,2,5]); -} -test_simplify_path_indexed(); diff --git a/wiring.scad b/wiring.scad index 5918347..0eb1266 100644 --- a/wiring.scad +++ b/wiring.scad @@ -88,7 +88,7 @@ module wiring(path, wires, wirediam=2, rounding=10, wirenum=0, bezsteps=12) { ]; offsets = hex_offsets(wires, wirediam); bezpath = fillet_path(path, rounding); - poly = simplify_path(path3d(bezier_path(bezpath, bezsteps))); + poly = path_merge_collinear(path3d(bezier_path(bezpath, bezsteps))); n = max(segs(wirediam), 8); r = wirediam/2; for (i = [0:1:wires-1]) {