mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Various arrays.scad docs updates. Bugfixes.
This commit is contained in:
parent
330647dd18
commit
320518194f
13 changed files with 205 additions and 175 deletions
308
arrays.scad
308
arrays.scad
|
@ -24,7 +24,7 @@
|
||||||
// Returns true when the list have elements of same type up to the depth `depth`.
|
// 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.
|
// Booleans and numbers are not distinguinshed as of distinct types.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = the list to check
|
// l = the list to check
|
||||||
// depth = the lowest level the check is done
|
// depth = the lowest level the check is done
|
||||||
// Example:
|
// Example:
|
||||||
// a = is_homogeneous([[1,["a"]], [2,["b"]]]); // Returns true
|
// 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
|
// g = select(l, -2); // Returns 8
|
||||||
// h = select(l, [1:3]); // Returns [4,5,6]
|
// h = select(l, [1:3]); // Returns [4,5,6]
|
||||||
// i = select(l, [1,3]); // Returns [4,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.")
|
assert( is_list(list) || is_string(list), "Invalid list.")
|
||||||
let(l=len(list))
|
let(l=len(list))
|
||||||
l==0 ? []
|
l==0
|
||||||
: end==undef?
|
? []
|
||||||
is_num(start)?
|
: end==undef
|
||||||
list[ (start%l+l)%l ]
|
? is_num(start)
|
||||||
: assert( is_list(start) || is_range(start), "Invalid start parameter")
|
? list[ (start%l+l)%l ]
|
||||||
|
: assert( is_list(start) || is_range(start), "Invalid start parameter")
|
||||||
[for (i=start) list[ (i%l+l)%l ] ]
|
[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.")
|
assert(is_finite(end), "Invalid end parameter.")
|
||||||
let( s = (start%l+l)%l, e = (end%l+l)%l )
|
let( s = (start%l+l)%l, e = (end%l+l)%l )
|
||||||
(s <= e)? [for (i = [s:1:e]) list[i]]
|
(s <= e)
|
||||||
: concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]]) ;
|
? [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()
|
// Function: last()
|
||||||
|
@ -97,19 +99,22 @@ function select(list, start, end=undef) =
|
||||||
// Example:
|
// Example:
|
||||||
// l = [3,4,5,6,7,8,9];
|
// l = [3,4,5,6,7,8,9];
|
||||||
// x = last(l); // Returns 9.
|
// x = last(l); // Returns 9.
|
||||||
function last(list) = list[len(list)-1];
|
function last(list) =
|
||||||
|
list[len(list)-1];
|
||||||
|
|
||||||
|
|
||||||
// Function: delete_last()
|
// Function: delete_last()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = delete_last(list);
|
// list = delete_last(list);
|
||||||
// Description:
|
// Description:
|
||||||
// Returns a list of all but the last entry. If input is empty, returns empty list.
|
// Returns a list with all but the last entry from the input list. If input is empty, returns empty list.
|
||||||
// Usage:
|
// Example:
|
||||||
// delete_last(list)
|
// nlist = delete_last(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
||||||
function delete_last(list) =
|
function delete_last(list) =
|
||||||
assert(is_list(list))
|
assert(is_list(list))
|
||||||
list==[] ? [] : slice(list,0,-2);
|
list==[] ? [] : slice(list,0,-2);
|
||||||
|
|
||||||
|
|
||||||
// Function: slice()
|
// Function: slice()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = slice(list,start,end);
|
// list = slice(list,start,end);
|
||||||
|
@ -130,10 +135,11 @@ function slice(list,start,end) =
|
||||||
assert( is_list(list), "Invalid list" )
|
assert( is_list(list), "Invalid list" )
|
||||||
assert( is_finite(start) && is_finite(end), "Invalid number(s)" )
|
assert( is_finite(start) && is_finite(end), "Invalid number(s)" )
|
||||||
let( l = len(list) )
|
let( l = len(list) )
|
||||||
l==0 ? []
|
l==0
|
||||||
: let(
|
? []
|
||||||
s = start<0? (l+start): start,
|
: let(
|
||||||
e = end<0? (l+end+1): end
|
s = start<0? (l+start) : start,
|
||||||
|
e = end<0? (l+end+1) : end
|
||||||
) [for (i=[s:1:e-1]) if (e>s) list[i]];
|
) [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.
|
// a = in_list("bar", ["foo", "bar", "baz"]); // Returns true.
|
||||||
// b = in_list("bee", ["foo", "bar", "baz"]); // Returns false.
|
// b = in_list("bee", ["foo", "bar", "baz"]); // Returns false.
|
||||||
// c = in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true.
|
// 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)),
|
assert( is_list(list) && (is_undef(idx) || is_finite(idx)),
|
||||||
"Invalid input." )
|
"Invalid input." )
|
||||||
let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] )
|
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 :
|
(i>=len(n))? val :
|
||||||
[for (j=[1:1:n[i]]) repeat(val, n, i+1)];
|
[for (j=[1:1:n[i]]) repeat(val, n, i+1)];
|
||||||
|
|
||||||
|
|
||||||
// Function: list_range()
|
// Function: list_range()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = list_range(n, <s>, <e>);
|
// list = list_range(n=, <s=>, <e=>);
|
||||||
// list = list_range(n, <s>, <step>);
|
// list = list_range(n=, <s=>, <step=>);
|
||||||
// list = list_range(e, <step>);
|
// list = list_range(e=, <step=>);
|
||||||
// list = list_range(s, e, <step>);
|
// list = list_range(s=, e=, <step=>);
|
||||||
// Description:
|
// Description:
|
||||||
// Returns a list, counting up from starting value `s`, by `step` increments,
|
// 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`.
|
// 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`
|
// If both `n` and `e` are given, returns `n` values evenly spread from `s`
|
||||||
// to `e`, and `step` is ignored.
|
// to `e`, and `step` is ignored.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
// ---
|
||||||
// n = Desired number of values in returned list, if given.
|
// n = Desired number of values in returned list, if given.
|
||||||
// s = Starting value. Default: 0
|
// s = Starting value. Default: 0
|
||||||
// e = Ending value to stop at, if given.
|
// 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]
|
// 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]
|
// 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]]
|
// 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_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.")
|
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) )
|
let( step = (n!=undef && e!=undef)? (e-s)/(n-1) : default(step,1) )
|
||||||
is_undef(e) ?
|
is_undef(e)
|
||||||
assert( is_consistent([s, step]), "Incompatible data.")
|
? assert( is_consistent([s, step]), "Incompatible data.")
|
||||||
[for (i=[0:1:n-1]) s+step*i ]
|
[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] ;
|
[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.")
|
assert(is_list(list)||is_string(list), "Improper list or string.")
|
||||||
indices==[]? [] :
|
indices==[]? [] :
|
||||||
assert(is_vector(indices), "Indices must be a list of numbers.")
|
assert(is_vector(indices), "Indices must be a list of numbers.")
|
||||||
let( l = len(indices),
|
let(
|
||||||
end = l-(closed?0:1) )
|
l = len(indices),
|
||||||
[ for (i = [0:1:l-1])
|
end = l-(closed?0:1)
|
||||||
let(
|
) [
|
||||||
|
for (i = [0:1:l-1]) let(
|
||||||
a = list[indices[i]],
|
a = list[indices[i]],
|
||||||
b = list[indices[(i+1)%l]],
|
b = list[indices[(i+1)%l]],
|
||||||
eq = (a == b)? true :
|
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) =
|
function list_set(list=[],indices,values,dflt=0,minlen=0) =
|
||||||
assert(is_list(list))
|
assert(is_list(list))
|
||||||
!is_list(indices)? (
|
!is_list(indices)? (
|
||||||
(is_finite(indices) && indices<len(list))?
|
(is_finite(indices) && indices<len(list))
|
||||||
concat([for (i=idx(list)) i==indices? values : list[i]], repeat(dflt, minlen-len(list)))
|
? concat([for (i=idx(list)) i==indices? values : list[i]], repeat(dflt, minlen-len(list)))
|
||||||
: list_set(list,[indices],[values],dflt) )
|
: list_set(list,[indices],[values],dflt)
|
||||||
:indices==[] && values==[] ?
|
) :
|
||||||
concat(list, repeat(dflt, minlen-len(list)))
|
indices==[] && values==[]
|
||||||
:assert(is_vector(indices) && is_list(values) && len(values)==len(indices) ,
|
? concat(list, repeat(dflt, minlen-len(list)))
|
||||||
|
: assert(is_vector(indices) && is_list(values) && len(values)==len(indices),
|
||||||
"Index list and value list must have the same length")
|
"Index list and value list must have the same length")
|
||||||
let( midx = max(len(list)-1, max(indices)) )
|
let( midx = max(len(list)-1, max(indices)) )
|
||||||
[ for(i=[0:midx] )
|
[
|
||||||
let( j = search(i,indices,0),
|
for (i=[0:1:midx]) let(
|
||||||
k = j[0] )
|
j = search(i,indices,0),
|
||||||
|
k = j[0]
|
||||||
|
)
|
||||||
assert( len(j)<2, "Repeated indices are not allowed." )
|
assert( len(j)<2, "Repeated indices are not allowed." )
|
||||||
k!=undef ? values[k] :
|
k!=undef
|
||||||
i<len(list) ? list[i]:
|
? values[k]
|
||||||
dflt ,
|
: i<len(list) ? list[i] : dflt,
|
||||||
each repeat(dflt, minlen-max(len(list),max(indices)))
|
each repeat(dflt, minlen-max(len(list),max(indices)))
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -484,29 +496,31 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) =
|
||||||
// b = list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
|
// b = list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
|
||||||
function list_insert(list, indices, values) =
|
function list_insert(list, indices, values) =
|
||||||
assert(is_list(list))
|
assert(is_list(list))
|
||||||
!is_list(indices)?
|
!is_list(indices) ?
|
||||||
assert( is_finite(indices) && is_finite(values), "Invalid indices/values." )
|
assert( is_finite(indices) && is_finite(values), "Invalid indices/values." )
|
||||||
assert( indices<=len(list), "Indices 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] ] ),
|
for (i=idx(list)) each ( i==indices? [ values, list[i] ] : [ list[i] ] ),
|
||||||
if (indices==len(list)) values
|
if (indices==len(list)) values
|
||||||
]
|
] :
|
||||||
: indices==[] && values==[] ? list
|
indices==[] && values==[] ? list :
|
||||||
: assert( is_vector(indices) && is_list(values) && len(values)==len(indices) ,
|
assert( is_vector(indices) && is_list(values) && len(values)==len(indices),
|
||||||
"Index list and value list must have the same length")
|
"Index list and value list must have the same length")
|
||||||
assert( max(indices)<=len(list), "Indices must be <= len(list) ." )
|
assert( max(indices)<=len(list), "Indices must be <= len(list)." )
|
||||||
let( maxidx = max(indices),
|
let(
|
||||||
minidx = min(indices) )
|
maxidx = max(indices),
|
||||||
[ for(i=[0:1:minidx-1] ) list[i],
|
minidx = min(indices)
|
||||||
for(i=[minidx: min(maxidx, len(list)-1)] )
|
) [
|
||||||
let( j = search(i,indices,0),
|
for (i=[0:1:minidx-1] ) list[i],
|
||||||
k = j[0],
|
for (i=[minidx : min(maxidx, len(list)-1)] )
|
||||||
x = assert( len(j)<2, "Repeated indices are not allowed." )
|
let(
|
||||||
)
|
j = search(i,indices,0),
|
||||||
each ( k != undef ? [ values[k], list[i] ] : [ list[i] ] ),
|
k = j[0],
|
||||||
for(i=[min(maxidx, len(list)-1)+1:1:len(list)-1] ) list[i],
|
x = assert( len(j)<2, "Repeated indices are not allowed." )
|
||||||
if(maxidx==len(list)) values[max_index(indices)]
|
) each ( k != undef ? [ values[k], list[i] ] : [ list[i] ] ),
|
||||||
];
|
for ( i = [min(maxidx, len(list)-1)+1 : 1 : len(list)-1] ) list[i],
|
||||||
|
if (maxidx == len(list)) values[max_index(indices)]
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
// Function: list_remove()
|
// Function: list_remove()
|
||||||
|
@ -616,6 +630,8 @@ function list_bset(indexset, valuelist, dflt=0) =
|
||||||
// Returns the length of the shortest sublist in a list of lists.
|
// Returns the length of the shortest sublist in a list of lists.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// array = A list of lists.
|
// array = A list of lists.
|
||||||
|
// Example:
|
||||||
|
// slen = list_shortest([[3,4,5],[6,7,8,9]]); // Returns: 3
|
||||||
function list_shortest(array) =
|
function list_shortest(array) =
|
||||||
assert(is_list(array), "Invalid input." )
|
assert(is_list(array), "Invalid input." )
|
||||||
min([for (v = array) len(v)]);
|
min([for (v = array) len(v)]);
|
||||||
|
@ -628,6 +644,8 @@ function list_shortest(array) =
|
||||||
// Returns the length of the longest sublist in a list of lists.
|
// Returns the length of the longest sublist in a list of lists.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// array = A list of lists.
|
// array = A list of lists.
|
||||||
|
// Example:
|
||||||
|
// llen = list_longest([[3,4,5],[6,7,8,9]]); // Returns: 4
|
||||||
function list_longest(array) =
|
function list_longest(array) =
|
||||||
assert(is_list(array), "Invalid input." )
|
assert(is_list(array), "Invalid input." )
|
||||||
max([for (v = array) len(v)]);
|
max([for (v = array) len(v)]);
|
||||||
|
@ -641,8 +659,11 @@ function list_longest(array) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// array = A list.
|
// array = A list.
|
||||||
// minlen = The minimum length to pad the list to.
|
// minlen = The minimum length to pad the list to.
|
||||||
// fill = The value to pad the list with.
|
// fill = The value to pad the list with. Default: `undef`
|
||||||
function list_pad(array, minlen, fill=undef) =
|
// Example:
|
||||||
|
// list = [3,4,5];
|
||||||
|
// nlist = list_pad(list,5,23); // Returns: [3,4,5,23,23]
|
||||||
|
function list_pad(array, minlen, fill) =
|
||||||
assert(is_list(array), "Invalid input." )
|
assert(is_list(array), "Invalid input." )
|
||||||
concat(array,repeat(fill,minlen-len(array)));
|
concat(array,repeat(fill,minlen-len(array)));
|
||||||
|
|
||||||
|
@ -655,6 +676,9 @@ function list_pad(array, minlen, fill=undef) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// array = A list.
|
// array = A list.
|
||||||
// minlen = The minimum length to pad the list to.
|
// minlen = The minimum length to pad the list to.
|
||||||
|
// Example:
|
||||||
|
// list = [3,4,5,6,7,8];
|
||||||
|
// nlist = list_trim(list,4); // Returns: [3,4,5,6]
|
||||||
function list_trim(array, maxlen) =
|
function list_trim(array, maxlen) =
|
||||||
assert(is_list(array), "Invalid input." )
|
assert(is_list(array), "Invalid input." )
|
||||||
[for (i=[0:1:min(len(array),maxlen)-1]) array[i]];
|
[for (i=[0:1:min(len(array),maxlen)-1]) array[i]];
|
||||||
|
@ -669,7 +693,13 @@ function list_trim(array, maxlen) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// array = A list.
|
// array = A list.
|
||||||
// minlen = The minimum length to pad the list to.
|
// minlen = The minimum length to pad the list to.
|
||||||
// fill = The value to pad the list with.
|
// fill = The value to pad the list with. Default: `undef`
|
||||||
|
// Example:
|
||||||
|
// list = [3,4,5,6];
|
||||||
|
// nlist = list_fit(list,3); // Returns: [3,4,5]
|
||||||
|
// Example:
|
||||||
|
// list = [3,4,5,6];
|
||||||
|
// nlist = list_fit(list,6,23); // Returns: [3,4,5,6,23,23]
|
||||||
function list_fit(array, length, fill) =
|
function list_fit(array, length, fill) =
|
||||||
assert(is_list(array), "Invalid input." )
|
assert(is_list(array), "Invalid input." )
|
||||||
let(l=len(array))
|
let(l=len(array))
|
||||||
|
@ -699,7 +729,7 @@ function _valid_idx(idx,imin,imax) =
|
||||||
|
|
||||||
// Function: shuffle()
|
// Function: shuffle()
|
||||||
// Usage:
|
// Usage:
|
||||||
// shuffled = shuffle(list,<seed>)
|
// shuffled = shuffle(list,<seed>);
|
||||||
// Description:
|
// Description:
|
||||||
// Shuffles the input list into random order.
|
// Shuffles the input list into random order.
|
||||||
// If given a string, shuffles the characters within the string.
|
// If given a string, shuffles the characters within the string.
|
||||||
|
@ -708,11 +738,17 @@ function _valid_idx(idx,imin,imax) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to shuffle.
|
// list = The list to shuffle.
|
||||||
// seed = Optional random number seed for the shuffling.
|
// 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) =
|
function shuffle(list,seed) =
|
||||||
assert(is_list(list)||is_string(list), "Invalid input." )
|
assert(is_list(list)||is_string(list), "Invalid input." )
|
||||||
is_string(list)? str_join(shuffle([for (x = list) x],seed=seed)) :
|
is_string(list)? str_join(shuffle([for (x = list) x],seed=seed)) :
|
||||||
len(list)<=1 ? list :
|
len(list)<=1 ? list :
|
||||||
let (
|
let(
|
||||||
rval = is_num(seed) ? rands(0,1,len(list),seed_value=seed)
|
rval = is_num(seed) ? rands(0,1,len(list),seed_value=seed)
|
||||||
: rands(0,1,len(list)),
|
: rands(0,1,len(list)),
|
||||||
left = [for (i=[0:len(list)-1]) if (rval[i]< 0.5) list[i]],
|
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 ],
|
lesser = [ for (entry=arr) if (entry[_i] < pivot ) entry ],
|
||||||
equal = [ 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 ]
|
greater = [ for (entry=arr) if (entry[_i] > pivot ) entry ]
|
||||||
)
|
)
|
||||||
concat(
|
concat(
|
||||||
_sort_vectors(lesser, _i ),
|
_sort_vectors(lesser, _i ),
|
||||||
_sort_vectors(equal, _i+1 ),
|
_sort_vectors(equal, _i+1 ),
|
||||||
|
@ -900,6 +936,8 @@ function sortidx(list, idx=undef) =
|
||||||
// Returns a sorted list with all repeated items removed.
|
// Returns a sorted list with all repeated items removed.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to uniquify.
|
// 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) =
|
function unique(list) =
|
||||||
assert(is_list(list)||is_string(list), "Invalid input." )
|
assert(is_list(list)||is_string(list), "Invalid input." )
|
||||||
is_string(list)? str_join(unique([for (x = list) x])) :
|
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`.
|
// that `count[i]` gives the number of times that `sorted[i]` appears in `list`.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to analyze.
|
// 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) =
|
function unique_count(list) =
|
||||||
assert(is_list(list) || is_string(list), "Invalid input." )
|
assert(is_list(list) || is_string(list), "Invalid input." )
|
||||||
list == [] ? [[],[]] :
|
list == [] ? [[],[]] :
|
||||||
|
@ -931,21 +971,26 @@ function unique_count(list) =
|
||||||
|
|
||||||
// Function: idx()
|
// Function: idx()
|
||||||
// Usage:
|
// Usage:
|
||||||
// rng = idx(list, <step>, <end>, <start>);
|
// rng = idx(list, <s=>, <e=>, <step=>);
|
||||||
// for(i=idx(list, <step>, <end>, <start>)) ...
|
// for(i=idx(list, <s=>, <e=>, <step=>)) ...
|
||||||
// Description:
|
// Description:
|
||||||
// Returns the range of indexes for the given list.
|
// Returns the range of indexes for the given list.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to returns the index range of.
|
// 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
|
// 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):
|
// Example(2D):
|
||||||
// colors = ["red", "green", "blue"];
|
// colors = ["red", "green", "blue"];
|
||||||
// for (i=idx(colors)) right(20*i) color(colors[i]) circle(d=10);
|
// 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." )
|
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()
|
// Function: enumerate()
|
||||||
|
@ -975,7 +1020,7 @@ function enumerate(l,idx=undef) =
|
||||||
|
|
||||||
// Function: force_list()
|
// Function: force_list()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = force_list(value, <n>, <fill>)
|
// list = force_list(value, <n>, <fill>);
|
||||||
// Description:
|
// Description:
|
||||||
// Coerces non-list values into a list. Makes it easy to treat a scalar input
|
// 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.
|
// consistently as a singleton list, as well as list inputs.
|
||||||
|
@ -998,68 +1043,57 @@ function force_list(value, n=1, fill) =
|
||||||
|
|
||||||
// Function: pair()
|
// Function: pair()
|
||||||
// Usage:
|
// Usage:
|
||||||
// p = pair(v);
|
// p = pair(list, <wrap>);
|
||||||
// for (p = pair(v)) ... // p contains a list of two adjacent items.
|
// for (p = pair(list, <wrap>)) ... // On each iteration, p contains a list of two adjacent items.
|
||||||
// Description:
|
// Description:
|
||||||
// Takes a list, and returns a list of adjacent pairs from it.
|
// Takes a list, and returns a list of adjacent pairs from it, optionally wrapping back to the front.
|
||||||
// Example(2D): Note that the last point and first point do NOT get paired together.
|
// Arguments:
|
||||||
// for (p = pair(circle(d=20, $fn=12)))
|
// list = The list to iterate.
|
||||||
// move(p[0])
|
// wrap = If true, wrap back to the start from the end. ie: return the last and first items as the last pair. Default: false
|
||||||
// rot(from=BACK, to=p[1]-p[0])
|
// Example(2D): Does NOT wrap from end to start,
|
||||||
// trapezoid(w1=1, w2=0, h=norm(p[1]-p[0]), anchor=FRONT);
|
// 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:
|
// Example:
|
||||||
// l = ["A","B","C","D"];
|
// l = ["A","B","C","D"];
|
||||||
// echo([for (p=pair(l)) str(p.y,p.x)]); // Outputs: ["BA", "CB", "DC"]
|
// echo([for (p=pair(l)) str(p.y,p.x)]); // Outputs: ["BA", "CB", "DC"]
|
||||||
function pair(v) =
|
function pair(list, wrap=false) =
|
||||||
assert(is_list(v)||is_string(v), "Invalid input." )
|
assert(is_list(list)||is_string(list), "Invalid input." )
|
||||||
[for (i=[0:1:len(v)-2]) [v[i],v[i+1]]];
|
assert(is_bool(wrap))
|
||||||
|
let(
|
||||||
|
ll = len(list)
|
||||||
// Function: pair_wrap()
|
) wrap
|
||||||
// Usage:
|
? [for (i=[0:1:ll-1]) [list[i], list[(i+1) % ll]]]
|
||||||
// p = pair_wrap(v);
|
: [for (i=[0:1:ll-2]) [list[i], list[i+1]]];
|
||||||
// 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: triplet()
|
// Function: triplet()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = triplet(v);
|
// list = triplet(list, <wrap>);
|
||||||
// for (t = triplet(v)) ...
|
// for (t = triplet(list, <wrap>)) ...
|
||||||
// Description:
|
// 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:
|
// Example:
|
||||||
// l = ["A","B","C","D","E"];
|
// l = ["A","B","C","D","E"];
|
||||||
// echo([for (p=triplet(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "EDC"]
|
// echo([for (p=triplet(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "EDC"]
|
||||||
function triplet(v) =
|
// Example(2D):
|
||||||
assert(is_list(v)||is_string(v), "Invalid input." )
|
// path = [for (i=[0:24]) polar_to_xy(i*2, i*360/12)];
|
||||||
[for (i=[0:1:len(v)-3]) [v[i],v[i+1],v[i+2]]];
|
// for (t = triplet(path)) {
|
||||||
|
// a = t[0]; b = t[1]; c = t[2];
|
||||||
|
// v = unit(unit(a-b) + unit(c-b));
|
||||||
// Function: triplet_wrap()
|
// translate(b) rot(from=FWD,to=v) anchor_arrow2d();
|
||||||
// Usage:
|
// }
|
||||||
// list = triplet_wrap(v);
|
// stroke(path);
|
||||||
// for (t = triplet_wrap(v)) ...
|
function triplet(list, wrap=false) =
|
||||||
// Description:
|
assert(is_list(list)||is_string(list), "Invalid input." )
|
||||||
// Takes a list, and returns a list of adjacent triplets from it, wrapping around from the end to the start of the list.
|
assert(is_bool(wrap))
|
||||||
// Example:
|
let(
|
||||||
// l = ["A","B","C","D"];
|
ll = len(list)
|
||||||
// echo([for (p=triplet_wrap(l)) str(p.z,p.y,p.x)]); // Outputs: ["CBA", "DCB", "ADC", "BAD"]
|
) wrap
|
||||||
function triplet_wrap(v) =
|
? [for (i=[0:1:ll-1]) [ list[i], list[(i+1)%ll], list[(i+2)%ll] ]]
|
||||||
assert(is_list(v)||is_string(v), "Invalid input." )
|
: [for (i=[0:1:ll-3]) [ list[i], list[i+1], list[i+2] ]];
|
||||||
[for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)],v[(i+2)%len(v)]]];
|
|
||||||
|
|
||||||
|
|
||||||
// Function: permute()
|
// Function: permute()
|
||||||
|
@ -1305,7 +1339,7 @@ function zip(v1, v2, v3, fit=false, fill=undef) =
|
||||||
function block_matrix(M) =
|
function block_matrix(M) =
|
||||||
let(
|
let(
|
||||||
bigM = [for(bigrow = M) each zip(bigrow)],
|
bigM = [for(bigrow = M) each zip(bigrow)],
|
||||||
len0=len(bigM[0]),
|
len0 = len(bigM[0]),
|
||||||
badrows = [for(row=bigM) if (len(row)!=len0) 1]
|
badrows = [for(row=bigM) if (len(row)!=len0) 1]
|
||||||
)
|
)
|
||||||
assert(badrows==[], "Inconsistent or invalid input")
|
assert(badrows==[], "Inconsistent or invalid input")
|
||||||
|
@ -1381,7 +1415,9 @@ function array_group(v, cnt=2, dflt=0) =
|
||||||
// l = List to flatten.
|
// l = List to flatten.
|
||||||
// Example:
|
// Example:
|
||||||
// l = flatten([[1,2,3], [4,5,[6,7,8]]]); // returns [1,2,3,4,5,[6,7,8]]
|
// 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()
|
// Function: full_flatten()
|
||||||
|
@ -1394,7 +1430,9 @@ function flatten(l) = [for (a = l) each a];
|
||||||
// l = List to flatten.
|
// l = List to flatten.
|
||||||
// Example:
|
// Example:
|
||||||
// l = full_flatten([[1,2,3], [4,5,[6,7,8]]]); // returns [1,2,3,4,5,6,7,8]
|
// 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.
|
// Internal. Not exposed.
|
||||||
|
@ -1421,14 +1459,12 @@ function _array_dim_recurse(v) =
|
||||||
// Usage:
|
// Usage:
|
||||||
// dims = array_dim(v, <depth>);
|
// dims = array_dim(v, <depth>);
|
||||||
// Description:
|
// Description:
|
||||||
// Returns the size of a multi-dimensional array. Returns a list of
|
// Returns the size of a multi-dimensional array. Returns a list of dimension lengths. The length
|
||||||
// dimension lengths. The length of `v` is the dimension `0`. The
|
// of `v` is the dimension `0`. The length of the items in `v` is dimension `1`. The length of 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
|
||||||
// items in the items in `v` is dimension `2`, etc. For each dimension,
|
// that depth is inconsistent, `undef` will be returned. If no items of that dimension depth exist,
|
||||||
// if the length of items at that depth is inconsistent, `undef` will
|
// `0` is returned. Otherwise, the consistent length of items in that dimensional depth is
|
||||||
// be returned. If no items of that dimension depth exist, `0` is
|
// returned.
|
||||||
// returned. Otherwise, the consistent length of items in that
|
|
||||||
// dimensional depth is returned.
|
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// v = Array to get dimensions of.
|
// v = Array to get dimensions of.
|
||||||
// depth = Dimension to get size of. If not given, returns a list of dimension lengths.
|
// depth = Dimension to get size of. If not given, returns a list of dimension lengths.
|
||||||
|
|
|
@ -573,7 +573,7 @@ function find_anchor(anchor, geom) =
|
||||||
path = move(-point2d(cp), p=geom[1]),
|
path = move(-point2d(cp), p=geom[1]),
|
||||||
anchor = point2d(anchor),
|
anchor = point2d(anchor),
|
||||||
isects = [
|
isects = [
|
||||||
for (t=triplet_wrap(path)) let(
|
for (t=triplet(path,true)) let(
|
||||||
seg1 = [t[0],t[1]],
|
seg1 = [t[0],t[1]],
|
||||||
seg2 = [t[1],t[2]],
|
seg2 = [t[1],t[2]],
|
||||||
isect = ray_segment_intersection([[0,0],anchor], seg1),
|
isect = ray_segment_intersection([[0,0],anchor], seg1),
|
||||||
|
|
|
@ -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)],
|
uvals = [for (i=[0:1:segs]) lerp(start_u, end_u, i/segs)],
|
||||||
path = bezier_points(curve,uvals),
|
path = bezier_points(curve,uvals),
|
||||||
defl = max([
|
defl = max([
|
||||||
for (i=idx(path,end=-3)) let(
|
for (i=idx(path,e=-3)) let(
|
||||||
mp = (path[i] + path[i+2]) / 2
|
mp = (path[i] + path[i+2]) / 2
|
||||||
) norm(path[i+1] - mp)
|
) norm(path[i+1] - mp)
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -2004,7 +2004,7 @@ function _split_polygon_at_x(poly, x) =
|
||||||
) (min(xs) >= x || max(xs) <= x)? [poly] :
|
) (min(xs) >= x || max(xs) <= x)? [poly] :
|
||||||
let(
|
let(
|
||||||
poly2 = [
|
poly2 = [
|
||||||
for (p = pair_wrap(poly)) each [
|
for (p = pair(poly,true)) each [
|
||||||
p[0],
|
p[0],
|
||||||
if(
|
if(
|
||||||
(p[0].x < x && p[1].x > x) ||
|
(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] :
|
) (min(ys) >= y || max(ys) <= y)? [poly] :
|
||||||
let(
|
let(
|
||||||
poly2 = [
|
poly2 = [
|
||||||
for (p = pair_wrap(poly)) each [
|
for (p = pair(poly,true)) each [
|
||||||
p[0],
|
p[0],
|
||||||
if(
|
if(
|
||||||
(p[0].y < y && p[1].y > y) ||
|
(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] :
|
) (min(zs) >= z || max(zs) <= z)? [poly] :
|
||||||
let(
|
let(
|
||||||
poly2 = [
|
poly2 = [
|
||||||
for (p = pair_wrap(poly)) each [
|
for (p = pair(poly,true)) each [
|
||||||
p[0],
|
p[0],
|
||||||
if(
|
if(
|
||||||
(p[0].z < z && p[1].z > z) ||
|
(p[0].z < z && p[1].z > z) ||
|
||||||
|
|
|
@ -1124,7 +1124,7 @@ function worm(
|
||||||
],
|
],
|
||||||
maxang = 360 / segs(d/2),
|
maxang = 360 / segs(d/2),
|
||||||
refined_polars = [
|
refined_polars = [
|
||||||
for (i=idx(polars,end=-2)) let(
|
for (i=idx(polars,e=-2)) let(
|
||||||
delta = polars[i+1].x - polars[i].x,
|
delta = polars[i+1].x - polars[i].x,
|
||||||
steps = ceil(delta/maxang),
|
steps = ceil(delta/maxang),
|
||||||
step = delta/steps
|
step = delta/steps
|
||||||
|
|
|
@ -824,7 +824,7 @@ function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0,
|
||||||
[foundfrag, concat([path], remainder)]
|
[foundfrag, concat([path], remainder)]
|
||||||
) : let(
|
) : let(
|
||||||
fragend = select(foundfrag,-1),
|
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? (
|
) hits? (
|
||||||
let(
|
let(
|
||||||
// Found fragment intersects with initial path
|
// Found fragment intersects with initial path
|
||||||
|
|
|
@ -367,7 +367,7 @@ function linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg
|
||||||
for (path=rgn) let(
|
for (path=rgn) let(
|
||||||
p = cleanup_path(path),
|
p = cleanup_path(path),
|
||||||
path = is_undef(maxseg)? p : [
|
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))
|
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
||||||
lerp(seg.x, seg.y, [0:1/steps:1-EPSILON])
|
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(
|
for (pathnum = idx(rgn)) let(
|
||||||
p = cleanup_path(rgn[pathnum]),
|
p = cleanup_path(rgn[pathnum]),
|
||||||
path = is_undef(maxseg)? p : [
|
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))
|
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
||||||
lerp(seg.x, seg.y, [0:1/steps:1-EPSILON])
|
lerp(seg.x, seg.y, [0:1/steps:1-EPSILON])
|
||||||
],
|
],
|
||||||
|
|
|
@ -186,7 +186,7 @@ module stroke(
|
||||||
|
|
||||||
if (len(path[0]) == 2) {
|
if (len(path[0]) == 2) {
|
||||||
// Straight segments
|
// Straight segments
|
||||||
for (i = idx(path2,end=-2)) {
|
for (i = idx(path2,e=-2)) {
|
||||||
seg = select(path2,i,i+1);
|
seg = select(path2,i,i+1);
|
||||||
delt = seg[1] - seg[0];
|
delt = seg[1] - seg[0];
|
||||||
translate(seg[0]) {
|
translate(seg[0]) {
|
||||||
|
@ -234,7 +234,7 @@ module stroke(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quatsums = Q_Cumulative([
|
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),
|
vec1 = i==0? UP : unit(path2[i]-path2[i-1], UP),
|
||||||
vec2 = unit(path2[i+1]-path2[i], UP),
|
vec2 = unit(path2[i+1]-path2[i], UP),
|
||||||
axis = vector_axis(vec1,vec2),
|
axis = vector_axis(vec1,vec2),
|
||||||
|
@ -243,12 +243,12 @@ module stroke(
|
||||||
]);
|
]);
|
||||||
rotmats = [for (q=quatsums) Q_Matrix4(q)];
|
rotmats = [for (q=quatsums) Q_Matrix4(q)];
|
||||||
sides = [
|
sides = [
|
||||||
for (i = idx(path2,end=-2))
|
for (i = idx(path2,e=-2))
|
||||||
quantup(segs(max(widths[i],widths[i+1])/2),4)
|
quantup(segs(max(widths[i],widths[i+1])/2),4)
|
||||||
];
|
];
|
||||||
|
|
||||||
// Straight segments
|
// Straight segments
|
||||||
for (i = idx(path2,end=-2)) {
|
for (i = idx(path2,e=-2)) {
|
||||||
dist = norm(path2[i+1] - path2[i]);
|
dist = norm(path2[i+1] - path2[i]);
|
||||||
w1 = widths[i]/2;
|
w1 = widths[i]/2;
|
||||||
w2 = widths[i+1]/2;
|
w2 = widths[i+1]/2;
|
||||||
|
|
|
@ -460,7 +460,7 @@ function _skin_core(profiles, caps) =
|
||||||
vertices = [for (prof=profiles) each prof],
|
vertices = [for (prof=profiles) each prof],
|
||||||
plens = [for (prof=profiles) len(prof)],
|
plens = [for (prof=profiles) len(prof)],
|
||||||
sidefaces = [
|
sidefaces = [
|
||||||
for(pidx=idx(profiles,end=-2))
|
for(pidx=idx(profiles,e=-2))
|
||||||
let(
|
let(
|
||||||
prof1 = profiles[pidx%len(profiles)],
|
prof1 = profiles[pidx%len(profiles)],
|
||||||
prof2 = profiles[(pidx+1)%len(profiles)],
|
prof2 = profiles[(pidx+1)%len(profiles)],
|
||||||
|
|
|
@ -266,9 +266,9 @@ test_list_fit();
|
||||||
module test_idx() {
|
module test_idx() {
|
||||||
colors = ["red", "green", "blue", "cyan"];
|
colors = ["red", "green", "blue", "cyan"];
|
||||||
assert([for (i=idx(colors)) i] == [0,1,2,3]);
|
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,e=-2)) i] == [0,1,2]);
|
||||||
assert([for (i=idx(colors,start=1)) i] == [1,2,3]);
|
assert([for (i=idx(colors,s=1)) i] == [1,2,3]);
|
||||||
assert([for (i=idx(colors,start=1,end=-2)) i] == [1,2]);
|
assert([for (i=idx(colors,s=1,e=-2)) i] == [1,2]);
|
||||||
}
|
}
|
||||||
test_idx();
|
test_idx();
|
||||||
|
|
||||||
|
@ -449,31 +449,25 @@ test_force_list();
|
||||||
module test_pair() {
|
module test_pair() {
|
||||||
assert(pair([3,4,5,6]) == [[3,4], [4,5], [5,6]]);
|
assert(pair([3,4,5,6]) == [[3,4], [4,5], [5,6]]);
|
||||||
assert(pair("ABCD") == [["A","B"], ["B","C"], ["C","D"]]);
|
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();
|
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() {
|
module test_triplet() {
|
||||||
assert(triplet([3,4,5,6,7]) == [[3,4,5], [4,5,6], [5,6,7]]);
|
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("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();
|
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() {
|
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]) == [[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]]);
|
assert(permute([3,4,5,6],n=3) == [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]);
|
||||||
|
|
|
@ -394,7 +394,7 @@ module test_line_normal() {
|
||||||
assert(line_normal([[0,0],[0,-10]]) == [1,0]);
|
assert(line_normal([[0,0],[0,-10]]) == [1,0]);
|
||||||
assert(approx(line_normal([[0,0],[10,10]]), [-sqrt(2)/2,sqrt(2)/2]));
|
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];
|
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;
|
p1 = p.x;
|
||||||
p2 = p.y;
|
p2 = p.y;
|
||||||
n = unit(p2-p1);
|
n = unit(p2-p1);
|
||||||
|
@ -619,7 +619,7 @@ module test_circle_point_tangents() {
|
||||||
|
|
||||||
module test_tri_calc() {
|
module test_tri_calc() {
|
||||||
sides = rands(1,100,100,seed_value=8888);
|
sides = rands(1,100,100,seed_value=8888);
|
||||||
for (p=pair_wrap(sides)) {
|
for (p=pair(sides,true)) {
|
||||||
opp = p[0];
|
opp = p[0];
|
||||||
adj = p[1];
|
adj = p[1];
|
||||||
hyp = norm([opp,adj]);
|
hyp = norm([opp,adj]);
|
||||||
|
@ -642,7 +642,7 @@ module test_tri_calc() {
|
||||||
|
|
||||||
module test_tri_functions() {
|
module test_tri_functions() {
|
||||||
sides = rands(1,100,100,seed_value=8181);
|
sides = rands(1,100,100,seed_value=8181);
|
||||||
for (p = pair_wrap(sides)) {
|
for (p = pair(sides,true)) {
|
||||||
adj = p.x;
|
adj = p.x;
|
||||||
opp = p.y;
|
opp = p.y;
|
||||||
hyp = norm([opp,adj]);
|
hyp = norm([opp,adj]);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
BOSL_VERSION = [2,0,539];
|
BOSL_VERSION = [2,0,540];
|
||||||
|
|
||||||
|
|
||||||
// Section: BOSL Library Version Functions
|
// Section: BOSL Library Version Functions
|
||||||
|
|
8
vnf.scad
8
vnf.scad
|
@ -674,7 +674,7 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
||||||
varr = vnf[0],
|
varr = vnf[0],
|
||||||
faces = vnf[1],
|
faces = vnf[1],
|
||||||
edges = sort([
|
edges = sort([
|
||||||
for (face=faces, edge=pair_wrap(face))
|
for (face=faces, edge=pair(face,true))
|
||||||
edge[0]<edge[1]? edge : [edge[1],edge[0]]
|
edge[0]<edge[1]? edge : [edge[1],edge[0]]
|
||||||
]),
|
]),
|
||||||
edgecnts = unique_count(edges),
|
edgecnts = unique_count(edges),
|
||||||
|
@ -732,8 +732,8 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
||||||
for(i = idx(faces), j = idx(faces)) if(i != j)
|
for(i = idx(faces), j = idx(faces)) if(i != j)
|
||||||
if(len(deduplicate(faces[i],closed=true))>=3)
|
if(len(deduplicate(faces[i],closed=true))>=3)
|
||||||
if(len(deduplicate(faces[j],closed=true))>=3)
|
if(len(deduplicate(faces[j],closed=true))>=3)
|
||||||
for(edge1 = pair_wrap(faces[i]))
|
for(edge1 = pair(faces[i],true))
|
||||||
for(edge2 = pair_wrap(faces[j]))
|
for(edge2 = pair(faces[j],true))
|
||||||
if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering.
|
if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering.
|
||||||
if(_edge_not_reported(edge1, varr, overpop_edges))
|
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],
|
f1 = faces[i],
|
||||||
f2 = faces[j],
|
f2 = faces[j],
|
||||||
shared_edges = [
|
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]<edge1[1]? edge1 : [edge1[1],edge1[0]],
|
e1 = edge1[0]<edge1[1]? edge1 : [edge1[1],edge1[0]],
|
||||||
e2 = edge2[0]<edge2[1]? edge2 : [edge2[1],edge2[0]]
|
e2 = edge2[0]<edge2[1]? edge2 : [edge2[1],edge2[0]]
|
||||||
) if (e1==e2) 1
|
) if (e1==e2) 1
|
||||||
|
|
Loading…
Reference in a new issue