From bf97d1c5bedc1b6ea0188d2ef7300c447f9fa95f Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Mon, 15 May 2023 18:51:37 -0400 Subject: [PATCH 1/2] Negative indexing in list_set and list_insert --- lists.scad | 79 +++++++++++++++++++++++++++++-------------- tests/test_lists.scad | 12 ++++++- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/lists.scad b/lists.scad index c83ca85..8ca1586 100644 --- a/lists.scad +++ b/lists.scad @@ -377,7 +377,7 @@ function bselect(list,index) = // Description: // Generates a list of `n` copies of the given value `val`. // If the count `n` is given as a list of counts, then this creates a -// multi-dimensional array, filled with `val`. +// multi-dimensional array, filled with `val`. If `n` is negative, returns the empty list. // Arguments: // val = The value to repeat to make the list or array. // n = The number of copies to make of `val`. Can be a list to make an array of copies. @@ -386,6 +386,7 @@ function bselect(list,index) = // b = repeat(8, [2,3]); // Returns [[8,8,8], [8,8,8]] // c = repeat(0, [2,2,3]); // Returns [[[0,0,0],[0,0,0]], [[0,0,0],[0,0,0]]] // d = repeat([1,2,3],3); // Returns [[1,2,3], [1,2,3], [1,2,3]] +// e = repeat(4, -1); // Returns [] function repeat(val, n, i=0) = is_num(n)? [for(j=[1:1:n]) val] : assert( is_list(n), "Invalid count number.") @@ -633,7 +634,9 @@ function list_pad(list, minlen, fill) = // Description: // Takes the input list and returns a new list such that `list[indices[i]] = values[i]` for all of // the (index,value) pairs supplied and unchanged for other indices. If you supply `indices` that are -// beyond the length of the list then the list is extended and filled in with the `dflt` value. +// larger that the length of the list then the list is extended and filled in with the `dflt` value. +// If you specify indices smaller than zero then they index from the end, with -1 being the last element. +// Negative indexing does not wrap around: an error occurs if you give a value smaller than `-len(list)`. // If you set `minlen` then the list is lengthed, if necessary, by padding with `dflt` to that length. // Repetitions in `indices` are not allowed. The lists `indices` and `values` must have the same length. // If `indices` is given as a scalar, then that index of the given `list` will be set to the scalar value of `values`. @@ -646,29 +649,45 @@ function list_pad(list, minlen, fill) = // Example: // a = list_set([2,3,4,5], 2, 21); // Returns: [2,3,21,5] // b = list_set([2,3,4,5], [1,3], [81,47]); // Returns: [2,81,4,47] -function list_set(list=[],indices,values,dflt=0,minlen=0) = +function list_set(list=[],indices,values,dflt=0,minlen=0) = assert(is_list(list)) - !is_list(indices)? ( - (is_finite(indices) && indices=0, str("Index ",indices," is smaller than negative list length")) + ( + index=0, "Index list contains value smaller than negative list length") + [ + for (i=[0:1:midx]) + let( + j = search(i,indices,0), + k = j[0] + ) + assert( len(j)<2, "Repeated indices are not allowed." ) + k!=undef ? values[k] + : i=0, "Index is too small, must be >= len(list)") assert( indices<=len(list), "Indices must be <= len(list) ." ) [ for (i=idx(list)) each ( i==indices? [ values, list[i] ] : [ list[i] ] ), @@ -701,9 +724,13 @@ function list_insert(list, indices, values) = "Index list and value list must have the same length") assert( max(indices)<=len(list), "Indices must be <= len(list)." ) let( + indices = [for(ind=indices) ind<0 ? ind+len(list) : ind], maxidx = max(indices), minidx = min(indices) - ) [ + ) + assert(minidx>=0, "Index list contains values that are too small") + assert(maxidx<=len(list), "Index list contains values that are too large") + [ for (i=[0:1:minidx-1] ) list[i], for (i=[minidx : min(maxidx, len(list)-1)] ) let( diff --git a/tests/test_lists.scad b/tests/test_lists.scad index 0ff0dc2..29ffa7d 100644 --- a/tests/test_lists.scad +++ b/tests/test_lists.scad @@ -160,7 +160,15 @@ module test_list_set() { assert_equal(list_set([1,2,3], 1, 4, dflt=12, minlen=5), [1,4,3,12,12]); assert_equal(list_set([1,2,3], [],[],dflt=12, minlen=5), [1,2,3,12,12]); assert_equal(list_set([1,2,3], 5,9), [1,2,3,0,0,9]); - assert_equal(list_set([1,2,3], 5,9,dflt=12), [1,2,3,12,12,9]); + assert_equal(list_set([1,2,3], 5,9,minlen=4), [1,2,3,0,0,9]); + assert_equal(list_set([1,2,3], 5,9,minlen=7), [1,2,3,0,0,9,0]); + assert_equal(list_set([1,2,3], 5,9,dflt=12), [1,2,3,12,12,9]); + assert_equal(list_set([1,2,3], -1,12), [1,2,12]); + assert_equal(list_set([1,2,3], -1,12,minlen=5), [1,2,12,0,0]); + assert_equal(list_set([1,2,3], [-2,5], [8,9]), [1,8,3,0,0,9]); + assert_equal(list_set([1,2,3], [-2,5], [8,9],minlen=8,dflt=-1), [1,8,3,-1,-1,9,-1,-1]); + assert_equal(list_set([1,2,3], [-2,5], [8,9],minlen=3,dflt=-1), [1,8,3,-1,-1,9]); + assert_equal(list_set([1,2,3], [0],[4], minlen=5), [4,2,3,0,0]); } test_list_set(); @@ -213,6 +221,8 @@ module test_list_insert() { assert_equal(list_insert([3],[0,1], [1,2]), [1,3,2]); assert_equal(list_insert([1,2,3],[],[]),[1,2,3]); assert_equal(list_insert([], 0, 4),[4]); + assert_equal(list_insert([1,2,3],-2,4), [1,4,2,3]); + assert_equal(list_insert([1,2,3,4,5], [-1,-3],[12,9]), [1,2,9,3,4,12,5]); } test_list_insert(); From fcfa1568c03baa5235a69563462213a17334455f Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Mon, 15 May 2023 20:02:07 -0400 Subject: [PATCH 2/2] bug fix --- rounding.scad | 8 ++++---- tests/test_lists.scad | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rounding.scad b/rounding.scad index 6495889..ea5a977 100644 --- a/rounding.scad +++ b/rounding.scad @@ -365,7 +365,7 @@ include // Example(2D,Med,NoAxes): Specifying by corner index. Use {{list_set()}} to construct the full chamfer cut list. // path = star(47, ir=25, or=50); // long path, lots of corners // chamfind = [8, 28, 60]; // But only want 3 chamfers -// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path)-1); +// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path)); // rpath = round_corners(path, cut=chamfcut, method="chamfer"); // polygon(rpath); // Example(2D,Med,NoAxes): Two-pass to chamfer and round by index. Use {{repeat_entries()}} to correct for first pass chamfers. @@ -373,9 +373,9 @@ include // path = star(47, ir=32, or=65); // long path, lots of corners // chamfind = [8, 28, 60]; // But only want 3 chamfers // roundind = [7,9,27,29,59,61]; // And 6 roundovers -// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path)-1); -// roundcut = list_set([],roundind,repeat(8,6),minlen=len(path)-1); -// dups = list_set([], chamfind, repeat(2,len(chamfind)), dflt=1, minlen=len(path)-1); +// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path)); +// roundcut = list_set([],roundind,repeat(8,6),minlen=len(path)); +// dups = list_set([], chamfind, repeat(2,len(chamfind)), dflt=1, minlen=len(path)); // rpath1 = round_corners(path, cut=chamfcut, method="chamfer"); // rpath2 = round_corners(rpath1, cut=repeat_entries(roundcut,dups)); // polygon(rpath2); diff --git a/tests/test_lists.scad b/tests/test_lists.scad index 29ffa7d..63b33bc 100644 --- a/tests/test_lists.scad +++ b/tests/test_lists.scad @@ -169,6 +169,8 @@ module test_list_set() { assert_equal(list_set([1,2,3], [-2,5], [8,9],minlen=8,dflt=-1), [1,8,3,-1,-1,9,-1,-1]); assert_equal(list_set([1,2,3], [-2,5], [8,9],minlen=3,dflt=-1), [1,8,3,-1,-1,9]); assert_equal(list_set([1,2,3], [0],[4], minlen=5), [4,2,3,0,0]); + assert_equal(list_set([], 2,3), [0,0,3]); + assert_equal(list_set([], 2,3,minlen=5,dflt=1), [1,1,3,1,1]); } test_list_set(); @@ -209,7 +211,6 @@ module test_list_remove_values() { assert_equal(list_remove_values(test,99,all=true), test); assert_equal(list_remove_values(test,[99,100],all=true), test); assert_equal(list_remove_values(test,[99,100]), test); - } test_list_remove_values();