diff --git a/arrays.scad b/arrays.scad
index 93a5fc5..728cc47 100644
--- a/arrays.scad
+++ b/arrays.scad
@@ -53,6 +53,150 @@ function _same_type(a,b, depth) =
&& []==[for(i=idx(a)) if( ! _same_type(a[i],b[i],depth-1) ) 0] );
+
+
+// Function: list_shortest()
+// Usage:
+// llen = list_shortest(array);
+// Topics: List Handling
+// See Also: list_longest()
+// Description:
+// Returns the length of the shortest sublist in a list of lists.
+// Arguments:
+// array = A list of lists.
+// Example:
+// slen = list_shortest([[3,4,5],[6,7,8,9]]); // Returns: 3
+function list_shortest(array) =
+ assert(is_list(array), "Invalid input." )
+ min([for (v = array) len(v)]);
+
+
+// Function: list_longest()
+// Usage:
+// llen = list_longest(array);
+// Topics: List Handling
+// See Also: list_shortest()
+// Description:
+// Returns the length of the longest sublist in a list of lists.
+// Arguments:
+// array = A list of lists.
+// Example:
+// llen = list_longest([[3,4,5],[6,7,8,9]]); // Returns: 4
+function list_longest(array) =
+ assert(is_list(array), "Invalid input." )
+ max([for (v = array) len(v)]);
+
+
+
+// Function: in_list()
+// Usage:
+// bool = in_list(val, list, [idx]);
+// Topics: List Handling
+// Description:
+// Returns true if value `val` is in list `list`. When `val==NAN` the answer will be false for any list.
+// Arguments:
+// val = The simple value to search for.
+// list = The list to search.
+// idx = If given, searches the given columns for matches for `val`.
+// Example:
+// 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) =
+ 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] )
+ s==[] || s==[[]] ? false
+ : is_undef(idx) ? val==list[s]
+ : val==list[s][idx];
+
+
+// Function: find_first_match()
+// Topics: List Handling
+// See Also: in_list()
+// Usage:
+// idx = find_first_match(val, list, [start=], [eps=]);
+// indices = find_first_match(val, list, all=true, [start=], [eps=]);
+// Description:
+// Finds the first item in `list` that matches `val`, returning the index.
+// Arguments:
+// val = The value to search for. If given a function literal of signature `function (x)`, uses that function to check list items. Returns true for a match.
+// list = The list to search through.
+// ---
+// start = The index to start searching from.
+// all = If true, returns a list of all matching item indices.
+// eps = The maximum allowed floating point rounding error for numeric comparisons.
+function find_first_match(val, list, start=0, all=false, eps=EPSILON) =
+ all? [
+ for (i=[start:1:len(list)-1])
+ if (
+ (!is_func(val) && approx(val, list[i], eps=eps)) ||
+ (is_func(val) && val(list[i]))
+ ) i
+ ] :
+ __find_first_match(val, list, eps=eps, i=start);
+
+function __find_first_match(val, list, eps, i=0) =
+ i >= len(list)? undef :
+ (
+ (!is_func(val) && approx(val, list[i], eps=eps)) ||
+ (is_func(val) && val(list[i]))
+ )? i : __find_first_match(val, list, eps=eps, i=i+1);
+
+
+// Function: list_increasing()
+// Usage:
+// bool = list_increasing(list);
+// Topics: List Handling
+// See Also: max_index(), min_index(), list_decreasing()
+// Description:
+// Returns true if the list is (non-strictly) increasing
+// Example:
+// a = list_increasing([1,2,3,4]); // Returns: true
+// b = list_increasing([1,3,2,4]); // Returns: false
+// c = list_increasing([4,3,2,1]); // Returns: false
+function list_increasing(list) =
+ assert(is_list(list)||is_string(list))
+ len([for (p=pair(list)) if(p.x>p.y) true])==0;
+
+
+// Function: list_decreasing()
+// Usage:
+// bool = list_decreasing(list);
+// Topics: List Handling
+// See Also: max_index(), min_index(), list_increasing()
+// Description:
+// Returns true if the list is (non-strictly) decreasing
+// Example:
+// a = list_decreasing([1,2,3,4]); // Returns: false
+// b = list_decreasing([4,2,3,1]); // Returns: false
+// c = list_decreasing([4,3,2,1]); // Returns: true
+function list_decreasing(list) =
+ assert(is_list(list)||is_string(list))
+ len([for (p=pair(list)) if(p.x
=len(array) , "Improper index list." )
+ is_string(array)? str_join(bselect( [for (x=array) x], index)) :
+ [for(i=[0:len(array)-1]) if (index[i]) array[i]];
+
+
+
+
+
+// Section: List Construction
+
+
// Function: list()
// Topics: List Handling, Type Conversion
// Usage:
@@ -246,155 +416,6 @@ function force_list(value, n=1, fill) =
is_undef(fill)? [for (i=[1:1:n]) value] : [value, for (i=[2:1:n]) fill];
-// Function: add_scalar()
-// Usage:
-// v = add_scalar(v, s);
-// Topics: List Handling
-// Description:
-// Given a list and a scalar, returns the list with the scalar added to each item in it.
-// If given a list of arrays, recursively adds the scalar to the each array.
-// Arguments:
-// v = The initial array.
-// s = A scalar value to add to every item in the array.
-// Example:
-// a = add_scalar([1,2,3],3); // Returns: [4,5,6]
-// b = add_scalar([[1,2,3],[3,4,5]],3); // Returns: [[4,5,6],[6,7,8]]
-function add_scalar(v,s) =
- is_finite(s) ? [for (x=v) is_list(x)? add_scalar(x,s) : is_finite(x) ? x+s: x] : v;
-
-
-// Function: in_list()
-// Usage:
-// bool = in_list(val, list, [idx]);
-// Topics: List Handling
-// Description:
-// Returns true if value `val` is in list `list`. When `val==NAN` the answer will be false for any list.
-// Arguments:
-// val = The simple value to search for.
-// list = The list to search.
-// idx = If given, searches the given columns for matches for `val`.
-// Example:
-// 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) =
- 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] )
- s==[] || s==[[]] ? false
- : is_undef(idx) ? val==list[s]
- : val==list[s][idx];
-
-
-// Function: find_first_match()
-// Topics: List Handling
-// See Also: in_list()
-// Usage:
-// idx = find_first_match(val, list, [start=], [eps=]);
-// indices = find_first_match(val, list, all=true, [start=], [eps=]);
-// Description:
-// Finds the first item in `list` that matches `val`, returning the index.
-// Arguments:
-// val = The value to search for. If given a function literal of signature `function (x)`, uses that function to check list items. Returns true for a match.
-// list = The list to search through.
-// ---
-// start = The index to start searching from.
-// all = If true, returns a list of all matching item indices.
-// eps = The maximum allowed floating point rounding error for numeric comparisons.
-function find_first_match(val, list, start=0, all=false, eps=EPSILON) =
- all? [
- for (i=[start:1:len(list)-1])
- if (
- (!is_func(val) && approx(val, list[i], eps=eps)) ||
- (is_func(val) && val(list[i]))
- ) i
- ] :
- __find_first_match(val, list, eps=eps, i=start);
-
-function __find_first_match(val, list, eps, i=0) =
- i >= len(list)? undef :
- (
- (!is_func(val) && approx(val, list[i], eps=eps)) ||
- (is_func(val) && val(list[i]))
- )? i : __find_first_match(val, list, eps=eps, i=i+1);
-
-
-// Function: min_index()
-// Usage:
-// idx = min_index(vals);
-// idxlist = min_index(vals, all=true);
-// Topics: List Handling
-// See Also: max_index(), list_increasing(), list_decreasing()
-// Description:
-// Returns the index of the first occurrence of the minimum value in the given list.
-// If `all` is true then returns a list of all indices where the minimum value occurs.
-// Arguments:
-// vals = vector of values
-// all = set to true to return indices of all occurences of the minimum. Default: false
-// Example:
-// a = min_index([5,3,9,6,2,7,8,2,1]); // Returns: 8
-// b = min_index([5,3,9,6,2,7,8,2,7],all=true); // Returns: [4,7]
-function min_index(vals, all=false) =
- assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
- all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
-
-
-// Function: max_index()
-// Usage:
-// idx = max_index(vals);
-// idxlist = max_index(vals, all=true);
-// Topics: List Handling
-// See Also: min_index(), list_increasing(), list_decreasing()
-// Description:
-// Returns the index of the first occurrence of the maximum value in the given list.
-// If `all` is true then returns a list of all indices where the maximum value occurs.
-// Arguments:
-// vals = vector of values
-// all = set to true to return indices of all occurences of the maximum. Default: false
-// Example:
-// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
-// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
-function max_index(vals, all=false) =
- assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
- all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
-
-
-// Function: list_increasing()
-// Usage:
-// bool = list_increasing(list);
-// Topics: List Handling
-// See Also: max_index(), min_index(), list_decreasing()
-// Description:
-// Returns true if the list is (non-strictly) increasing
-// Example:
-// a = list_increasing([1,2,3,4]); // Returns: true
-// b = list_increasing([1,3,2,4]); // Returns: false
-// c = list_increasing([4,3,2,1]); // Returns: false
-function list_increasing(list) =
- assert(is_list(list)||is_string(list))
- len([for (p=pair(list)) if(p.x>p.y) true])==0;
-
-
-// Function: list_decreasing()
-// Usage:
-// bool = list_decreasing(list);
-// Topics: List Handling
-// See Also: max_index(), min_index(), list_increasing()
-// Description:
-// Returns true if the list is (non-strictly) decreasing
-// Example:
-// a = list_decreasing([1,2,3,4]); // Returns: false
-// b = list_decreasing([4,2,3,1]); // Returns: false
-// c = list_decreasing([4,3,2,1]); // Returns: true
-function list_decreasing(list) =
- assert(is_list(list)||is_string(list))
- len([for (p=pair(list)) if(p.xlen(valuelist)), str("List `valuelist` too short; its length should be ",len(trueind)) )
+ assert( !(len(trueind)=len(array) , "Improper index list." )
- is_string(array)? str_join(bselect( [for (x=array) x], index)) :
- [for(i=[0:len(array)-1]) if (index[i]) array[i]];
-
-
-// Function: list_bset()
-// Usage:
-// arr = list_bset(indexset, valuelist, [dflt]);
-// Topics: List Handling
-// See Also: bselect()
-// Description:
-// Opposite of `bselect()`. Returns a list the same length as `indexlist`, where each item will
-// either be 0 if the corresponding item in `indexset` is false, or the next sequential value
-// from `valuelist` if the item is true. The number of `true` values in `indexset` must be equal
-// to the length of `valuelist`.
-// Arguments:
-// indexset = A list of boolean values.
-// valuelist = The list of values to set into the returned list.
-// dflt = Default value to store when the indexset item is false.
-// Example:
-// a = list_bset([false,true,false,true,false], [3,4]); // Returns: [0,3,0,4,0]
-// b = list_bset([false,true,false,true,false], [3,4], dflt=1); // Returns: [1,3,1,4,1]
-function list_bset(indexset, valuelist, dflt=0) =
- assert(is_list(indexset), "The index set is not a list." )
- assert(is_list(valuelist), "The `valuelist` is not a list." )
- let( trueind = search([true], indexset,0)[0] )
- assert( !(len(trueind)>len(valuelist)), str("List `valuelist` too short; its length should be ",len(trueind)) )
- assert( !(len(trueind)0 , "Invalid or empty list of numbers.")
+ all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
+
+
+// Function: max_index()
+// Usage:
+// idx = max_index(vals);
+// idxlist = max_index(vals, all=true);
+// Topics: List Handling
+// See Also: min_index(), list_increasing(), list_decreasing()
+// Description:
+// Returns the index of the first occurrence of the maximum value in the given list.
+// If `all` is true then returns a list of all indices where the maximum value occurs.
+// Arguments:
+// vals = vector of values
+// all = set to true to return indices of all occurences of the maximum. Default: false
+// Example:
+// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
+// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
+function max_index(vals, all=false) =
+ assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
+ all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
+
+
// Section: Vector Searching
-
// Function: closest_point()
// Usage:
// index = closest_point(pt, points);