diff --git a/arrays.scad b/arrays.scad index 42b2c05..6c64c20 100644 --- a/arrays.scad +++ b/arrays.scad @@ -24,7 +24,7 @@ // Returns true when the list have elements of same type up to the depth `depth`. // Booleans and numbers are not distinguinshed as of distinct types. // Arguments: -// list = the list to check +// l = the list to check // depth = the lowest level the check is done // Example: // a = is_homogeneous([[1,["a"]], [2,["b"]]]); // Returns true @@ -71,20 +71,22 @@ function _same_type(a,b, depth) = // g = select(l, -2); // Returns 8 // h = select(l, [1:3]); // Returns [4,5,6] // i = select(l, [1,3]); // Returns [4,6] -function select(list, start, end=undef) = +function select(list, start, end) = assert( is_list(list) || is_string(list), "Invalid list.") let(l=len(list)) - l==0 ? [] - : end==undef? - is_num(start)? - list[ (start%l+l)%l ] - : assert( is_list(start) || is_range(start), "Invalid start parameter") + l==0 + ? [] + : end==undef + ? is_num(start) + ? list[ (start%l+l)%l ] + : assert( is_list(start) || is_range(start), "Invalid start parameter") [for (i=start) list[ (i%l+l)%l ] ] - : assert(is_finite(start), "Invalid start parameter.") + : assert(is_finite(start), "Invalid start parameter.") assert(is_finite(end), "Invalid end parameter.") let( s = (start%l+l)%l, e = (end%l+l)%l ) - (s <= e)? [for (i = [s:1:e]) list[i]] - : concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]]) ; + (s <= e) + ? [for (i = [s:1:e]) list[i]] + : concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]]) ; // Function: last() @@ -97,19 +99,22 @@ function select(list, start, end=undef) = // Example: // l = [3,4,5,6,7,8,9]; // x = last(l); // Returns 9. -function last(list) = list[len(list)-1]; +function last(list) = + list[len(list)-1]; + // Function: delete_last() // Usage: // list = delete_last(list); // Description: -// Returns a list of all but the last entry. If input is empty, returns empty list. -// Usage: -// delete_last(list) +// Returns a list with all but the last entry from the input list. If input is empty, returns empty list. +// Example: +// nlist = delete_last(["foo", "bar", "baz"]); // Returns: ["foo", "bar"] function delete_last(list) = assert(is_list(list)) list==[] ? [] : slice(list,0,-2); + // Function: slice() // Usage: // list = slice(list,start,end); @@ -130,10 +135,11 @@ function slice(list,start,end) = assert( is_list(list), "Invalid list" ) assert( is_finite(start) && is_finite(end), "Invalid number(s)" ) let( l = len(list) ) - l==0 ? [] - : let( - s = start<0? (l+start): start, - e = end<0? (l+end+1): end + l==0 + ? [] + : let( + s = start<0? (l+start) : start, + e = end<0? (l+end+1) : end ) [for (i=[s:1:e-1]) if (e>s) list[i]]; @@ -150,7 +156,7 @@ function slice(list,start,end) = // a = in_list("bar", ["foo", "bar", "baz"]); // Returns true. // b = in_list("bee", ["foo", "bar", "baz"]); // Returns false. // c = in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true. -function in_list(val,list,idx=undef) = +function in_list(val,list,idx) = assert( is_list(list) && (is_undef(idx) || is_finite(idx)), "Invalid input." ) let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] ) @@ -248,18 +254,20 @@ function repeat(val, n, i=0) = (i>=len(n))? val : [for (j=[1:1:n[i]]) repeat(val, n, i+1)]; + // Function: list_range() // Usage: -// list = list_range(n, , ); -// list = list_range(n, , ); -// list = list_range(e, ); -// list = list_range(s, e, ); +// list = list_range(n=, , ); +// list = list_range(n=, , ); +// list = list_range(e=, ); +// list = list_range(s=, e=, ); // Description: // Returns a list, counting up from starting value `s`, by `step` increments, // until either `n` values are in the list, or it reaches the end value `e`. // If both `n` and `e` are given, returns `n` values evenly spread from `s` // to `e`, and `step` is ignored. // Arguments: +// --- // n = Desired number of values in returned list, if given. // s = Starting value. Default: 0 // e = Ending value to stop at, if given. @@ -275,14 +283,14 @@ function repeat(val, n, i=0) = // h = list_range(s=3, e=8, step=2); // Returns [3,5,7] // i = list_range(s=4, e=8.3, step=2); // Returns [4,6,8] // j = list_range(n=4, s=[3,4], step=[2,3]); // Returns [[3,4], [5,7], [7,10], [9,13]] -function list_range(n=undef, s=0, e=undef, step=undef) = +function list_range(n, s=0, e, step) = assert( is_undef(n) || is_finite(n), "Parameter `n` must be a number.") assert( is_undef(n) || is_undef(e) || is_undef(step), "At most 2 of n, e, and step can be given.") let( step = (n!=undef && e!=undef)? (e-s)/(n-1) : default(step,1) ) - is_undef(e) ? - assert( is_consistent([s, step]), "Incompatible data.") + is_undef(e) + ? assert( is_consistent([s, step]), "Incompatible data.") [for (i=[0:1:n-1]) s+step*i ] - : assert( is_vector([s,step,e]), "Start `s`, step `step` and end `e` must be numbers.") + : assert( is_vector([s,step,e]), "Start `s`, step `step` and end `e` must be numbers.") [for (v=[s:step:e]) v] ; @@ -379,10 +387,11 @@ function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) = assert(is_list(list)||is_string(list), "Improper list or string.") indices==[]? [] : assert(is_vector(indices), "Indices must be a list of numbers.") - let( l = len(indices), - end = l-(closed?0:1) ) - [ for (i = [0:1:l-1]) - let( + let( + l = len(indices), + end = l-(closed?0:1) + ) [ + for (i = [0:1:l-1]) let( a = list[indices[i]], b = list[indices[(i+1)%l]], eq = (a == b)? true : @@ -455,22 +464,25 @@ function repeat_entries(list, N, exact=true) = function list_set(list=[],indices,values,dflt=0,minlen=0) = assert(is_list(list)) !is_list(indices)? ( - (is_finite(indices) && indices) +// shuffled = shuffle(list,); // Description: // Shuffles the input list into random order. // If given a string, shuffles the characters within the string. @@ -708,11 +738,17 @@ function _valid_idx(idx,imin,imax) = // Arguments: // list = The list to shuffle. // seed = Optional random number seed for the shuffling. +// Example: +// // Spades Hearts Diamonds Clubs +// suits = ["\u2660", "\u2661", "\u2662", "\u2663"]; +// ranks = [2,3,4,5,6,7,8,9,10,"J","Q","K","A"]; +// cards = [for (suit=suits, rank=ranks) str(rank,suit)]; +// deck = shuffle(cards); function shuffle(list,seed) = assert(is_list(list)||is_string(list), "Invalid input." ) is_string(list)? str_join(shuffle([for (x = list) x],seed=seed)) : len(list)<=1 ? list : - let ( + let( rval = is_num(seed) ? rands(0,1,len(list),seed_value=seed) : rands(0,1,len(list)), left = [for (i=[0:len(list)-1]) if (rval[i]< 0.5) list[i]], @@ -743,7 +779,7 @@ function _sort_vectors(arr, _i=0) = lesser = [ for (entry=arr) if (entry[_i] < pivot ) entry ], equal = [ for (entry=arr) if (entry[_i] == pivot ) entry ], greater = [ for (entry=arr) if (entry[_i] > pivot ) entry ] - ) + ) concat( _sort_vectors(lesser, _i ), _sort_vectors(equal, _i+1 ), @@ -900,6 +936,8 @@ function sortidx(list, idx=undef) = // Returns a sorted list with all repeated items removed. // Arguments: // list = The list to uniquify. +// Example: +// sorted = unique([5,2,8,3,1,3,8,7,5]); // Returns: [1,2,3,5,7,8] function unique(list) = assert(is_list(list)||is_string(list), "Invalid input." ) is_string(list)? str_join(unique([for (x = list) x])) : @@ -919,6 +957,8 @@ function unique(list) = // that `count[i]` gives the number of times that `sorted[i]` appears in `list`. // Arguments: // list = The list to analyze. +// Example: +// sorted = unique([5,2,8,3,1,3,8,3,5]); // Returns: [ [1,2,3,5,8], [1,1,3,2,2] ] function unique_count(list) = assert(is_list(list) || is_string(list), "Invalid input." ) list == [] ? [[],[]] : @@ -931,21 +971,26 @@ function unique_count(list) = // Function: idx() // Usage: -// rng = idx(list, , , ); -// for(i=idx(list, , , )) ... +// rng = idx(list, , , ); +// for(i=idx(list, , , )) ... // Description: // Returns the range of indexes for the given list. // Arguments: // list = The list to returns the index range of. +// s = The starting index. Default: 0 +// e = The delta from the end of the list. Default: -1 (end of list) // step = The step size to stride through the list. Default: 1 -// end = The delta from the end of the list. Default: -1 -// start = The starting index. Default: 0 // Example(2D): // colors = ["red", "green", "blue"]; // for (i=idx(colors)) right(20*i) color(colors[i]) circle(d=10); -function idx(list, step=1, end=-1,start=0) = +function idx(list, s=0, e=-1, step=1) = assert(is_list(list)||is_string(list), "Invalid input." ) - [start : step : len(list)+end]; + let( ll = len(list) ) + ll == 0 ? [0:1:-1] : + let( + _s = posmod(s,ll), + _e = posmod(e,ll) + ) [_s : step : _e]; // Function: enumerate() @@ -975,7 +1020,7 @@ function enumerate(l,idx=undef) = // Function: force_list() // Usage: -// list = force_list(value, , ) +// list = force_list(value, , ); // Description: // Coerces non-list values into a list. Makes it easy to treat a scalar input // consistently as a singleton list, as well as list inputs. @@ -998,68 +1043,57 @@ function force_list(value, n=1, fill) = // Function: pair() // Usage: -// p = pair(v); -// for (p = pair(v)) ... // p contains a list of two adjacent items. +// p = pair(list, ); +// for (p = pair(list, )) ... // On each iteration, p contains a list of two adjacent items. // Description: -// Takes a list, and returns a list of adjacent pairs from it. -// Example(2D): Note that the last point and first point do NOT get paired together. -// for (p = pair(circle(d=20, $fn=12))) -// move(p[0]) -// rot(from=BACK, to=p[1]-p[0]) -// trapezoid(w1=1, w2=0, h=norm(p[1]-p[0]), anchor=FRONT); +// Takes a list, and returns a list of adjacent pairs from it, optionally wrapping back to the front. +// Arguments: +// list = The list to iterate. +// wrap = If true, wrap back to the start from the end. ie: return the last and first items as the last pair. Default: false +// Example(2D): Does NOT wrap from end to start, +// for (p = pair(circle(d=40, $fn=12))) +// stroke(p, endcap2="arrow2"); +// Example(2D): Wraps around from end to start. +// for (p = pair(circle(d=40, $fn=12), wrap=true)) +// stroke(p, endcap2="arrow2"); // Example: // l = ["A","B","C","D"]; // echo([for (p=pair(l)) str(p.y,p.x)]); // Outputs: ["BA", "CB", "DC"] -function pair(v) = - assert(is_list(v)||is_string(v), "Invalid input." ) - [for (i=[0:1:len(v)-2]) [v[i],v[i+1]]]; - - -// Function: pair_wrap() -// Usage: -// p = pair_wrap(v); -// for (p = pair_wrap(v)) ... -// Description: -// Takes a list, and returns a list of adjacent pairs from it, wrapping around from the end to the start of the list. -// Example(2D): -// for (p = pair_wrap(circle(d=20, $fn=12))) -// move(p[0]) -// rot(from=BACK, to=p[1]-p[0]) -// trapezoid(w1=1, w2=0, h=norm(p[1]-p[0]), anchor=FRONT); -// Example: -// l = ["A","B","C","D"]; -// echo([for (p=pair_wrap(l)) str(p.y,p.x)]); // Outputs: ["BA", "CB", "DC", "AD"] -function pair_wrap(v) = - assert(is_list(v)||is_string(v), "Invalid input." ) - [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)]]]; +function pair(list, wrap=false) = + assert(is_list(list)||is_string(list), "Invalid input." ) + assert(is_bool(wrap)) + let( + ll = len(list) + ) wrap + ? [for (i=[0:1:ll-1]) [list[i], list[(i+1) % ll]]] + : [for (i=[0:1:ll-2]) [list[i], list[i+1]]]; // Function: triplet() // Usage: -// list = triplet(v); -// for (t = triplet(v)) ... +// list = triplet(list, ); +// for (t = triplet(list, )) ... // Description: -// Takes a list, and returns a list of adjacent triplets from it. +// Takes a list, and returns a list of adjacent triplets from it, optionally wrapping back to the front. // Example: // l = ["A","B","C","D","E"]; // echo([for (p=triplet(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "EDC"] -function triplet(v) = - assert(is_list(v)||is_string(v), "Invalid input." ) - [for (i=[0:1:len(v)-3]) [v[i],v[i+1],v[i+2]]]; - - -// Function: triplet_wrap() -// Usage: -// list = triplet_wrap(v); -// for (t = triplet_wrap(v)) ... -// Description: -// Takes a list, and returns a list of adjacent triplets from it, wrapping around from the end to the start of the list. -// Example: -// l = ["A","B","C","D"]; -// echo([for (p=triplet_wrap(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "ADC", "BAD"] -function triplet_wrap(v) = - assert(is_list(v)||is_string(v), "Invalid input." ) - [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)],v[(i+2)%len(v)]]]; +// Example(2D): +// path = [for (i=[0:24]) polar_to_xy(i*2, i*360/12)]; +// for (t = triplet(path)) { +// a = t[0]; b = t[1]; c = t[2]; +// v = unit(unit(a-b) + unit(c-b)); +// translate(b) rot(from=FWD,to=v) anchor_arrow2d(); +// } +// stroke(path); +function triplet(list, wrap=false) = + assert(is_list(list)||is_string(list), "Invalid input." ) + assert(is_bool(wrap)) + let( + ll = len(list) + ) wrap + ? [for (i=[0:1:ll-1]) [ list[i], list[(i+1)%ll], list[(i+2)%ll] ]] + : [for (i=[0:1:ll-3]) [ list[i], list[i+1], list[i+2] ]]; // Function: permute() @@ -1305,7 +1339,7 @@ function zip(v1, v2, v3, fit=false, fill=undef) = function block_matrix(M) = let( bigM = [for(bigrow = M) each zip(bigrow)], - len0=len(bigM[0]), + len0 = len(bigM[0]), badrows = [for(row=bigM) if (len(row)!=len0) 1] ) assert(badrows==[], "Inconsistent or invalid input") @@ -1381,7 +1415,9 @@ function array_group(v, cnt=2, dflt=0) = // l = List to flatten. // Example: // l = flatten([[1,2,3], [4,5,[6,7,8]]]); // returns [1,2,3,4,5,[6,7,8]] -function flatten(l) = [for (a = l) each a]; +function flatten(l) = + !is_list(l)? l : + [for (a=l) if (is_list(a)) (each a) else a]; // Function: full_flatten() @@ -1394,7 +1430,9 @@ function flatten(l) = [for (a = l) each a]; // l = List to flatten. // Example: // l = full_flatten([[1,2,3], [4,5,[6,7,8]]]); // returns [1,2,3,4,5,6,7,8] -function full_flatten(l) = [for(a=l) if(is_list(a)) (each full_flatten(a)) else a ]; +function full_flatten(l) = + !is_list(l)? l : + [for (a=l) if (is_list(a)) (each full_flatten(a)) else a]; // Internal. Not exposed. @@ -1421,14 +1459,12 @@ function _array_dim_recurse(v) = // Usage: // dims = array_dim(v, ); // Description: -// Returns the size of a multi-dimensional array. Returns a list of -// dimension lengths. The length of `v` is the dimension `0`. The -// length of the items in `v` is dimension `1`. The length of the -// items in the items in `v` is dimension `2`, etc. For each dimension, -// if the length of items at that depth is inconsistent, `undef` will -// be returned. If no items of that dimension depth exist, `0` is -// returned. Otherwise, the consistent length of items in that -// dimensional depth is returned. +// Returns the size of a multi-dimensional array. Returns a list of dimension lengths. The length +// of `v` is the dimension `0`. The length of the items in `v` is dimension `1`. The length of the +// items in the items in `v` is dimension `2`, etc. For each dimension, if the length of items at +// that depth is inconsistent, `undef` will be returned. If no items of that dimension depth exist, +// `0` is returned. Otherwise, the consistent length of items in that dimensional depth is +// returned. // Arguments: // v = Array to get dimensions of. // depth = Dimension to get size of. If not given, returns a list of dimension lengths. diff --git a/attachments.scad b/attachments.scad index b93171b..be4ec9e 100644 --- a/attachments.scad +++ b/attachments.scad @@ -573,7 +573,7 @@ function find_anchor(anchor, geom) = path = move(-point2d(cp), p=geom[1]), anchor = point2d(anchor), isects = [ - for (t=triplet_wrap(path)) let( + for (t=triplet(path,true)) let( seg1 = [t[0],t[1]], seg2 = [t[1],t[2]], isect = ray_segment_intersection([[0,0],anchor], seg1), diff --git a/beziers.scad b/beziers.scad index c1ddb86..4162a17 100644 --- a/beziers.scad +++ b/beziers.scad @@ -345,7 +345,7 @@ function bezier_segment_length(curve, start_u=0, end_u=1, max_deflect=0.01) = uvals = [for (i=[0:1:segs]) lerp(start_u, end_u, i/segs)], path = bezier_points(curve,uvals), defl = max([ - for (i=idx(path,end=-3)) let( + for (i=idx(path,e=-3)) let( mp = (path[i] + path[i+2]) / 2 ) norm(path[i+1] - mp) ]), diff --git a/geometry.scad b/geometry.scad index b5a4c23..52f03c2 100644 --- a/geometry.scad +++ b/geometry.scad @@ -2004,7 +2004,7 @@ function _split_polygon_at_x(poly, x) = ) (min(xs) >= x || max(xs) <= x)? [poly] : let( poly2 = [ - for (p = pair_wrap(poly)) each [ + for (p = pair(poly,true)) each [ p[0], if( (p[0].x < x && p[1].x > x) || @@ -2034,7 +2034,7 @@ function _split_polygon_at_y(poly, y) = ) (min(ys) >= y || max(ys) <= y)? [poly] : let( poly2 = [ - for (p = pair_wrap(poly)) each [ + for (p = pair(poly,true)) each [ p[0], if( (p[0].y < y && p[1].y > y) || @@ -2064,7 +2064,7 @@ function _split_polygon_at_z(poly, z) = ) (min(zs) >= z || max(zs) <= z)? [poly] : let( poly2 = [ - for (p = pair_wrap(poly)) each [ + for (p = pair(poly,true)) each [ p[0], if( (p[0].z < z && p[1].z > z) || diff --git a/involute_gears.scad b/involute_gears.scad index 1cb9842..90859a4 100644 --- a/involute_gears.scad +++ b/involute_gears.scad @@ -1124,7 +1124,7 @@ function worm( ], maxang = 360 / segs(d/2), refined_polars = [ - for (i=idx(polars,end=-2)) let( + for (i=idx(polars,e=-2)) let( delta = polars[i+1].x - polars[i].x, steps = ceil(delta/maxang), step = delta/steps diff --git a/paths.scad b/paths.scad index 9e7afcc..bba6a49 100644 --- a/paths.scad +++ b/paths.scad @@ -824,7 +824,7 @@ function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, [foundfrag, concat([path], remainder)] ) : let( fragend = select(foundfrag,-1), - hits = [for (i = idx(path,end=-2)) if(approx(path[i],fragend,eps=eps)) i] + hits = [for (i = idx(path,e=-2)) if(approx(path[i],fragend,eps=eps)) i] ) hits? ( let( // Found fragment intersects with initial path diff --git a/regions.scad b/regions.scad index 25a0bd7..7eee696 100644 --- a/regions.scad +++ b/regions.scad @@ -367,7 +367,7 @@ function linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg for (path=rgn) let( p = cleanup_path(path), path = is_undef(maxseg)? p : [ - for (seg=pair_wrap(p)) each + for (seg=pair(p,true)) each let(steps=ceil(norm(seg.y-seg.x)/maxseg)) lerp(seg.x, seg.y, [0:1/steps:1-EPSILON]) ] @@ -380,7 +380,7 @@ function linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg for (pathnum = idx(rgn)) let( p = cleanup_path(rgn[pathnum]), path = is_undef(maxseg)? p : [ - for (seg=pair_wrap(p)) each + for (seg=pair(p,true)) each let(steps=ceil(norm(seg.y-seg.x)/maxseg)) lerp(seg.x, seg.y, [0:1/steps:1-EPSILON]) ], diff --git a/shapes2d.scad b/shapes2d.scad index 35d1387..bbd3fd1 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -186,7 +186,7 @@ module stroke( if (len(path[0]) == 2) { // Straight segments - for (i = idx(path2,end=-2)) { + for (i = idx(path2,e=-2)) { seg = select(path2,i,i+1); delt = seg[1] - seg[0]; translate(seg[0]) { @@ -234,7 +234,7 @@ module stroke( } } else { quatsums = Q_Cumulative([ - for (i = idx(path2,end=-2)) let( + for (i = idx(path2,e=-2)) let( vec1 = i==0? UP : unit(path2[i]-path2[i-1], UP), vec2 = unit(path2[i+1]-path2[i], UP), axis = vector_axis(vec1,vec2), @@ -243,12 +243,12 @@ module stroke( ]); rotmats = [for (q=quatsums) Q_Matrix4(q)]; sides = [ - for (i = idx(path2,end=-2)) + for (i = idx(path2,e=-2)) quantup(segs(max(widths[i],widths[i+1])/2),4) ]; // Straight segments - for (i = idx(path2,end=-2)) { + for (i = idx(path2,e=-2)) { dist = norm(path2[i+1] - path2[i]); w1 = widths[i]/2; w2 = widths[i+1]/2; diff --git a/skin.scad b/skin.scad index 07381ca..e8faf66 100644 --- a/skin.scad +++ b/skin.scad @@ -460,7 +460,7 @@ function _skin_core(profiles, caps) = vertices = [for (prof=profiles) each prof], plens = [for (prof=profiles) len(prof)], sidefaces = [ - for(pidx=idx(profiles,end=-2)) + for(pidx=idx(profiles,e=-2)) let( prof1 = profiles[pidx%len(profiles)], prof2 = profiles[(pidx+1)%len(profiles)], diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index aac41d4..ce7cbfd 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -266,9 +266,9 @@ test_list_fit(); module test_idx() { colors = ["red", "green", "blue", "cyan"]; assert([for (i=idx(colors)) i] == [0,1,2,3]); - assert([for (i=idx(colors,end=-2)) i] == [0,1,2]); - assert([for (i=idx(colors,start=1)) i] == [1,2,3]); - assert([for (i=idx(colors,start=1,end=-2)) i] == [1,2]); + assert([for (i=idx(colors,e=-2)) i] == [0,1,2]); + assert([for (i=idx(colors,s=1)) i] == [1,2,3]); + assert([for (i=idx(colors,s=1,e=-2)) i] == [1,2]); } test_idx(); @@ -449,31 +449,25 @@ test_force_list(); module test_pair() { assert(pair([3,4,5,6]) == [[3,4], [4,5], [5,6]]); assert(pair("ABCD") == [["A","B"], ["B","C"], ["C","D"]]); + assert(pair([3,4,5,6],true) == [[3,4], [4,5], [5,6], [6,3]]); + assert(pair("ABCD",true) == [["A","B"], ["B","C"], ["C","D"], ["D","A"]]); + assert(pair([3,4,5,6],wrap=true) == [[3,4], [4,5], [5,6], [6,3]]); + assert(pair("ABCD",wrap=true) == [["A","B"], ["B","C"], ["C","D"], ["D","A"]]); } test_pair(); -module test_pair_wrap() { - assert(pair_wrap([3,4,5,6]) == [[3,4], [4,5], [5,6], [6,3]]); - assert(pair_wrap("ABCD") == [["A","B"], ["B","C"], ["C","D"], ["D","A"]]); -} -test_pair_wrap(); - - module test_triplet() { assert(triplet([3,4,5,6,7]) == [[3,4,5], [4,5,6], [5,6,7]]); assert(triplet("ABCDE") == [["A","B","C"], ["B","C","D"], ["C","D","E"]]); + assert(triplet([3,4,5,6],true) == [[3,4,5], [4,5,6], [5,6,3], [6,3,4]]); + assert(triplet("ABCD",true) == [["A","B","C"], ["B","C","D"], ["C","D","A"], ["D","A","B"]]); + assert(triplet([3,4,5,6],wrap=true) == [[3,4,5], [4,5,6], [5,6,3], [6,3,4]]); + assert(triplet("ABCD",wrap=true) == [["A","B","C"], ["B","C","D"], ["C","D","A"], ["D","A","B"]]); } test_triplet(); -module test_triplet_wrap() { - assert(triplet_wrap([3,4,5,6]) == [[3,4,5], [4,5,6], [5,6,3], [6,3,4]]); - assert(triplet_wrap("ABCD") == [["A","B","C"], ["B","C","D"], ["C","D","A"], ["D","A","B"]]); -} -test_triplet_wrap(); - - module test_permute() { assert(permute([3,4,5,6]) == [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]]); assert(permute([3,4,5,6],n=3) == [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]); diff --git a/tests/test_geometry.scad b/tests/test_geometry.scad index 63a1966..6dc8e02 100644 --- a/tests/test_geometry.scad +++ b/tests/test_geometry.scad @@ -394,7 +394,7 @@ module test_line_normal() { assert(line_normal([[0,0],[0,-10]]) == [1,0]); assert(approx(line_normal([[0,0],[10,10]]), [-sqrt(2)/2,sqrt(2)/2])); pts = [for (p=pair(rands(-100,100,1000,seed_value=4312))) p]; - for (p = pair_wrap(pts)) { + for (p = pair(pts,true)) { p1 = p.x; p2 = p.y; n = unit(p2-p1); @@ -619,7 +619,7 @@ module test_circle_point_tangents() { module test_tri_calc() { sides = rands(1,100,100,seed_value=8888); - for (p=pair_wrap(sides)) { + for (p=pair(sides,true)) { opp = p[0]; adj = p[1]; hyp = norm([opp,adj]); @@ -642,7 +642,7 @@ module test_tri_calc() { module test_tri_functions() { sides = rands(1,100,100,seed_value=8181); - for (p = pair_wrap(sides)) { + for (p = pair(sides,true)) { adj = p.x; opp = p.y; hyp = norm([opp,adj]); diff --git a/version.scad b/version.scad index 6886ffb..6d5fccb 100644 --- a/version.scad +++ b/version.scad @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,539]; +BOSL_VERSION = [2,0,540]; // Section: BOSL Library Version Functions diff --git a/vnf.scad b/vnf.scad index 19541ea..9e5ada8 100644 --- a/vnf.scad +++ b/vnf.scad @@ -674,7 +674,7 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) = varr = vnf[0], faces = vnf[1], edges = sort([ - for (face=faces, edge=pair_wrap(face)) + for (face=faces, edge=pair(face,true)) edge[0]=3) if(len(deduplicate(faces[j],closed=true))>=3) - for(edge1 = pair_wrap(faces[i])) - for(edge2 = pair_wrap(faces[j])) + for(edge1 = pair(faces[i],true)) + for(edge2 = pair(faces[j],true)) if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering. if(_edge_not_reported(edge1, varr, overpop_edges)) [ @@ -768,7 +768,7 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) = f1 = faces[i], f2 = faces[j], shared_edges = [ - for (edge1 = pair_wrap(f1), edge2 = pair_wrap(f2)) let( + for (edge1 = pair(f1,true), edge2 = pair(f2,true)) let( e1 = edge1[0]