diff --git a/arrays.scad b/arrays.scad index c1430014..ac97444b 100644 --- a/arrays.scad +++ b/arrays.scad @@ -209,7 +209,7 @@ function list_tail(list, from=1) = // If given a string, explodes it into a list of single letters. // Arguments: // l = The value to expand. -// See Also: scalar_vec3(), force_list(), range(), rangex() +// See Also: scalar_vec3(), force_list() // Example: // l1 = list([3:2:9]); // Returns: [3,5,7,9] // l2 = list([3,4,5]); // Returns: [3,4,5] @@ -396,7 +396,7 @@ function list_decreasing(list) = // Usage: // list = repeat(val, n); // Topics: List Handling -// See Also: range(), rangex() +// See Also: count(), lerpn() // Description: // Generates a list or array of `n` copies of the given value `val`. // If the count `n` is given as a list of counts, then this creates a @@ -416,89 +416,21 @@ function repeat(val, n, i=0) = [for (j=[1:1:n[i]]) repeat(val, n, i+1)]; -// Function: range() +// Function: count() // Usage: -// list = range(n, , ); -// list = range(n, , ); -// list = range(e=, ); -// list = range(s=, e=, ); -// Topics: List Handling +// list = count(n,,); // 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. +// Creates a list of `n` numbers, starting at `s`, incrementing by `step` each time. // Arguments: -// n = Desired number of values in returned list, if given. -// --- -// s = Starting value. Default: 0 -// e = Ending value to stop at, if given. -// step = Amount to increment each value. Default: 1 -// See Also: repeat(), rangex() +// n = The length of the list of numbers to create. +// s = The starting value of the list of numbers. +// step = The amount to increment successive numbers in the list. // Example: -// a = range(4); // Returns [0,1,2,3] -// b = range(n=4, step=2); // Returns [0,2,4,6] -// c = range(n=4, s=3, step=3); // Returns [3,6,9,12] -// d = range(n=5, s=0, e=10); // Returns [0, 2.5, 5, 7.5, 10] -// e = range(e=3); // Returns [0,1,2,3] -// f = range(e=7, step=2); // Returns [0,2,4,6] -// g = range(s=3, e=5); // Returns [3,4,5] -// h = range(s=3, e=8, step=2); // Returns [3,5,7] -// i = range(s=4, e=8.3, step=2); // Returns [4,6,8] -function 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.") - [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.") - [for (v=[s:step:e]) v] ; - +// nl1 = count(5); // Returns: [0,1,2,3,4] +// nl2 = count(5,3); // Returns: [3,4,5,6,7] +// nl3 = count(4,3,2); // Returns: [3,5,7,9] +function count(n,s=0,step=1) = [for (i=[0:1:n-1]) s+i*step]; -// Function: rangex() -// Usage: -// list = rangex(n, , ); -// list = rangex(n, , ); -// list = rangex(e=, ); -// list = rangex(s=, e=, ); -// Topics: List Handling -// 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 value just before the end value `e`. -// If both `n` and `e` are given, returns `n` values evenly spread from `s` to the value -// just before `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. -// step = Amount to increment each value. Default: 1 -// See Also: repeat(), range() -// Example: -// a = rangex(4); // Returns [0,1,2,3] -// b = rangex(5,e=1); // Returns [0, 0.2, 0.4, 0.6, 0.8] -// c = rangex(n=4, step=2); // Returns [0,2,4,6] -// d = rangex(n=4, step=0.25); // Returns [0, 0.25, 0.5, 0.75] -// e = rangex(n=4, s=3, step=3); // Returns [3,6,9,12] -// f = rangex(n=5, s=0, e=10); // Returns [0, 2, 4, 6, 8] -// g = rangex(e=3); // Returns [0,1,2] -// h = rangex(e=7, step=2); // Returns [0,2,4,6] -// i = rangex(s=3, e=5); // Returns [3,4] -// j = rangex(s=3, e=8, step=2); // Returns [3,5,7] -// k = rangex(s=2, e=8, step=2); // Returns [2,4,6] -// l = rangex(s=2, e=8.1, step=2); // Returns [2,4,6,8] -function rangex(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 : default(step,1) ) - 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.") - let(steps=floor((e-s)/step+0.5)) - [for (i=[0:1:steps-1]) s+step*i]; - // Section: List Manipulation diff --git a/beziers.scad b/beziers.scad index d6c2eb76..bd6a8f02 100644 --- a/beziers.scad +++ b/beziers.scad @@ -437,10 +437,8 @@ function bezier_curvature(curve, u) = // move_copies(bezier_curve(bez, 8)) sphere(r=1.5, $fn=12); // trace_bezier(bez, N=len(bez)-1); function bezier_curve(curve,n,endpoint=true) = - [ - each bezier_points(curve, rangex(endpoint?n-1:n,0,1)), - if (endpoint) last(curve) - ]; + bezier_points(curve, lerpn(0,1,n,endpoint)); + // Function: bezier_segment_closest_point() // Usage: @@ -509,7 +507,7 @@ function bezier_segment_closest_point(curve, pt, max_err=0.01, u=0, end_u=1) = function bezier_segment_length(curve, start_u=0, end_u=1, max_deflect=0.01) = let( segs = len(curve) * 2, - uvals = [for (i=[0:1:segs]) lerp(start_u, end_u, i/segs)], + uvals = lerpn(start_u, end_u, segs+1), path = bezier_points(curve,uvals), defl = max([ for (i=idx(path,e=-3)) let( @@ -693,7 +691,7 @@ function bezier_path_length(path, N=3, max_deflect=0.001) = // Function: bezier_path() // Usage: -// path = bezier_path(bezier, , ) +// path = bezier_path(bezier, , , ) // Topics: Bezier Paths // See Also: bezier_points(), bezier_curve() // Description: @@ -702,6 +700,7 @@ function bezier_path_length(path, N=3, max_deflect=0.001) = // bezier = A bezier path to approximate. // splinesteps = Number of straight lines to split each bezier segment into. default=16 // N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3 +// endpoint = If true, include the very last point of the bezier path. Default: true // Example(2D): // bez = [ // [0,0], [-5,30], @@ -711,18 +710,19 @@ function bezier_path_length(path, N=3, max_deflect=0.001) = // ]; // trace_path(bez, size=1, N=3, showpts=true); // trace_path(bezier_path(bez, N=3), size=3); -function bezier_path(bezier, splinesteps=16, N=3) = +function bezier_path(bezier, splinesteps=16, N=3, endpoint=true) = assert(is_path(bezier)) assert(is_int(N)) assert(is_int(splinesteps)) - assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1.")) + assert(len(bezier)%N == 1, str("A degree ",N," bezier path should have a multiple of ",N," points in it, plus 1.")) let( - segs = (len(bezier)-1)/N - ) deduplicate([ - for (seg = [0:1:segs-1], i = [0:1:splinesteps-1]) - bezier_path_point(bezier, seg, i/splinesteps, N=N), - bezier_path_point(bezier, segs-1, 1, N=N) - ]); + segs = (len(bezier)-1) / N, + step = 1 / splinesteps + ) [ + for (seg = [0:1:segs-1]) + each bezier_points(select(bezier, seg*N, (seg+1)*N), [0:step:1-step/2]), + if (endpoint) last(bezier) + ]; @@ -861,19 +861,18 @@ function bezier_close_to_axis(bezier, axis="X", N=3) = assert(is_int(N)) assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1.")) let( - bezend = len(bezier)-1, sp = bezier[0], - ep = bezier[bezend] + ep = last(bezier) ) (axis=="X")? concat( - [for (i=[0:1:N-1]) lerp([sp.x,0], sp, i/N)], - bezier, - [for (i=[1:1:N]) lerp(ep, [ep.x,0], i/N)], - [for (i=[1:1:N]) lerp([ep.x,0], [sp.x,0], i/N)] + lerpn([sp.x,0], sp, N, false), + list_head(bezier), + lerpn(ep, [ep.x,0], N, false), + lerpn([ep.x,0], [sp.x,0], N+1) ) : (axis=="Y")? concat( - [for (i=[0:1:N-1]) lerp([0,sp.y], sp, i/N)], - bezier, - [for (i=[1:1:N]) lerp(ep, [0,ep.y], i/N)], - [for (i=[1:1:N]) lerp([0,ep.y], [0,sp.y], i/N)] + lerpn([0,sp.y], sp, N, false), + list_head(bezier), + lerpn(ep, [0,ep.y], N, false), + lerpn([0,ep.y], [0,sp.y], N+1) ) : ( assert(in_list(axis, ["X","Y"])) ); @@ -907,10 +906,10 @@ function bezier_offset(offset, bezier, N=3) = backbez = reverse([ for (pt = bezier) pt+offset ]), bezend = len(bezier)-1 ) concat( - bezier, - [for (i=[1:1:N-1]) lerp(bezier[bezend], backbez[0], i/N)], - backbez, - [for (i=[1:1:N]) lerp(backbez[bezend], bezier[0], i/N)] + list_head(bezier), + lerpn(bezier[bezend], backbez[0], N, false), + list_head(backbez), + lerpn(backbez[bezend], bezier[0], N+1) ); diff --git a/fnliterals.scad b/fnliterals.scad new file mode 100644 index 00000000..ef46a2ab --- /dev/null +++ b/fnliterals.scad @@ -0,0 +1,1438 @@ +////////////////////////////////////////////////////////////////////// +// LibFile: fnliterals.scad +// Handlers for function literals, and Function literal generators. +// Includes: +// include +// include +// DefineHeader(Table:Positional|Definition||Named|Definition): FunctionLiteral Args +////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////// +// Section: Function Literal Algorithms + + +// Function: map() +// Topics: Function Literals, Looping +// Usage: +// lst = map(func, list); +// lst = map(function (x) x+1, list); +// Description: +// Applies the function `func` to all items in `list`, returning the list of results. +// In pseudo-code, this is effectively: +// ``` +// function map(func,list): +// out = []; +// foreach item in list: +// append func(item) to out; +// return out; +// ``` +// Arguments: +// func = The function of signature (x) to evaluate for each item in `list`. +// list = The input list. +// See Also: filter(), reduce(), accumulate(), while(), for_n() +// Example: +// func = function(x) x*x; +// echo(map(func, [1,2,3,4])); +// // ECHO: [1,4,9,16] +// Example: +// path = star(n=5,step=2,d=100); +// seglens = map(function (p) norm(p[1]-p[0]), pair(path,wrap=true)); +function map(func, list) = + assert(is_function(func)) + assert(is_list(list)) + [for (x=list) func(x)]; + + +// Function: filter() +// Topics: Function Literals, Looping, Filters +// Usage: +// lst = filter(func, list); +// lst = filter(function (x) x+1, list); +// Description: +// Returns all items in `list` that the function `func` returns true for. +// In pseudo-code, this is effectively: +// ``` +// function filter(func,list): +// out = []; +// foreach item in list: +// if func(item) is true: +// append item to out; +// return out; +// ``` +// Arguments: +// func = The function of signature `function (x)` to evaluate for each item in `list`. +// list = The input list. +// See Also: map(), reduce(), accumulate(), while(), for_n() +// Example: +// func = function(x) x>5; +// echo(filter(func, [3,4,5,6,7])); +// // ECHO: [6,7] +function filter(func, list) = + assert(is_function(func)) + assert(is_list(list)) + [for (x=list) if (func(x)) x]; + + +// Function: reduce() +// Topics: Function Literals, Looping +// Usage: +// res = reduce(func, list, ); +// res = reduce(function (a,b) a+b, list, ); +// res = accumulate(function (a,b) a+b, list, ); +// Description: +// First the accumulator is set to the value in `init`. Then, for each item in `list`, the function +// in `func` is called with the accumulator and that list item, and the result is stored in the +// acumulator for the next iteration. That value is also appended to the output list. Once all +// list items have been processed, the list of accumulator values is returned. +// In pseduo-code, this is effectively: +// ``` +// function accumulate(func, list, init=0): +// out = [] +// x = init; +// foreach item in list: +// x = func(x, item); +// append x to out; +// return out; +// ``` +// Arguments: +// func = The function of signature `function (a,b)` to evaluate for each item in `list`. Default: `f_add()` +// list = The input list. +// init = The starting value for the accumulator. Default: 0 +// See Also: map(), filter(), reduce(), while(), for_n() +// Examples: Reimplement cumsum() +// echo(accumulate(function (a,b) a+b, [3,4,5],0)); +// // ECHO: [3,7,12] +// Examples: Reimplement cumprod() +// echo(accumulate(f_mul(),[3,4,5],1)); +// // ECHO: [3,12,60,360] +function accumulate(func, list, init=0) = + assert(is_function(func)) + assert(is_list(list)) + let( + l = len(list), + a = function (x, i, out) + i >= l ? out : + let( x=func(x,list[i]) ) + a(x, i+1, [each out, x]) + ) a(init, 0, []); + + +// Function: while() +// Topics: Function Literals, Looping, Iteration +// Usage: +// x = while(init, cond, func); +// Description: +// Repeatedly calls the function literals in `cond` and `func` until the `cond` call returns false. +// Both `cond` and `func` have the signature `function (i,x)`. The variable `i` is passed the iteration +// number, starting with 0. On the first iteration, the variable `x` is given by `init`. On subsequent +// iterations, `x` is given by the results of the previous call to `func`. Returns the resulting `x` of +// the final iteration. In pseudo-code, this is effectively: +// ``` +// function while(init, cond, func): +// x = init; +// i = 0; +// while cond(i, x): +// x = func(i, x); +// i = i + 1; +// return x; +// ``` +// Arguments: +// init = The initial value for `x`. +// cond = A function literal with signature `function (i,x)`, called to determine if the loop should continue. Returns true if the loop should continue. +// func = A function literal with signature `function (i,x)`, called on each iteration. The returned value is passed as `x` on the next iteration. +// See Also: map(), filter(), reduce(), accumulate(), while(), for_n() +function while(init, cond, func) = + assert(is_function(cond)) + assert(is_function(func)) + let( a = function(x,i) cond(i,x) ? a(func(i,x),i+1) : x ) + a(init,0); + + +// Function: for_n() +// Topics: Function Literals, Looping, Iteration +// See Also: map(), filter(), reduce(), accumulate(), while() +// Usage: +// x = for_n(n, init, func); +// Description: +// Given the function literal `func`, with the signature `function (i,x)`, repeatedly calls it `n` times. +// If `n` is given as a scalar, the `i` value will traverse the range `[0:1:n-1]`, one value per call. +// If `n` is given as a range, the `i` value will traverse the given range, one value per call. +// The `x` value for the first iteration is given in `init`, and in all subsequent iterations `x` will be the result of the previous call. +// In pseudo-code, this is effectively: +// ``` +// function for_n(n, init, func): +// x = init; +// if is_range(n): +// iterate i over range n: +// x = func(i,x); +// else: +// iterate i from 0 to n-1 by 1: +// x = func(i,x); +// return x; +// ``` +// Arguments: +// n = The number of iterations to perform, or, if given as a range, the range to traverse. +// init = The initial value to pass as `x` to the function in `func`. +// func = The function literal to call, with signature `function (i,x)`. +// Example: +// fib = function(n) for_n( +// n, [], +// function(i,x) x? [x[1], x[0]+x[1]] : [0,1] +// )[1]; +function for_n(n,init,func) = + assert(is_finite(n)) + assert(is_function(func)) + let( + n = is_num(n)? [0:1:n-1] : n, + a = function(x,i) i <= n[2]? a(func(i,x), i+n[1]) : x + ) + a(init, n[0]); + + +// Function: find_first() +// Topics: Function Literals, Searching +// Usage: +// idx = find_first(val, list, , ); +// Description: +// Finds the first item in `list` which, when compared against `val` using the function literal +// `func` gets a true result. By default, `func` just calls `approx()`. The signature of the +// function literal in `func` is `function (a,b)`, and it is expected to return true when the +// two values compare as matching. It should return false otherwise. +// If you need to find *all* matching items in the list, you should probably use {{filter()]] instead. +// See Also: map(), filter(), reduce(), accumulate(), while(), for_n(), binsearch() +// Arguments: +// val = The value to look for. +// list = The list to search. +// --- +// start = The first item to check. +// func = The function literal to use to compare `val` against the items in `list`. Expects the signature `function (a,b)`, and a boolean return value. Default: `f_approx()` +function find_first(val, list, start=0, func=f_approx()) = + assert(is_list(list)) + assert(is_finite(start)) + assert(is_function(func)) + let( + l = len(list), + a = function(i) + i >= l? undef : + func(val, list[i])? i : + a(i+1) + ) + a(start); + + +// Function: binsearch() +// Topics: Function Literals, Data Structures, Searching +// Usage: +// idx = binsearch(key,list, ); +// Description: +// Searches a sorted list for an entry with the given key, using a binary search strategy. +// Returns the index of the matching item found. If none found, returns undef. +// Arguments: +// key = The key to look for. +// list = The list of items to search through. +// idx = If given, the index of the item sublists to use as the item key. +// cmp = The comparator function literal to use. Default: `f_cmp()` +// See Also: map(), filter(), reduce(), accumulate(), hashmap() +// Example: +// items = unique(rands(0,100,10000)); +// idx = binsearch(44, items); +// Example: +// items = unique(rands(0,100,10000)); +// idx = binsearch(44, items, cmp=function(a,b) a-b); +// Example: +// items = [for (i=[32:126]) [chr(i), i]]; +// idx = binsearch("G"", items, idx=0); +function binsearch(key, list, idx, cmp=f_cmp()) = + let( + a = function(s,e) + let( + p = floor((s+e)/2), + ikey = is_undef(idx)? list[p] : list[p][idx], + c = cmp(ikey,key) + ) + c == 0? p : + c > 0? (p == s? undef : a(s, p-1)) : + (p == e? undef : a(p+1, e)) + ) a(0,len(list)-1); + + +// Function: simple_hash() +// Topics: Function Literals, Hashing, Data Structures +// Usage: +// hx = simple_hash(x); +// Description: +// Given an arbitrary value, returns the integer hash value for it. +// Arguments: +// x = The value to get the simple hash value of. +// See Also: hashmap() +// Examples: +// x = simple_hash("Foobar"); +// x = simple_hash([[10,20],[-5,3]]); +function simple_hash(x) = + let( m = 0.5 * (sqrt(5) - 1) ) + is_num(x)? floor(m*x*256) : + is_list(x)? let( + l = len(x), + a = function(i,v) i>=l? v : a(i+1, m*v + simple_hash(x[i])) + ) floor(a(0,0)*4096) : let( + s = str(x), + l = len(s), + a = function(i,v) i>=l? v : a(i+1, m*v + ord(s[i])) + ) floor(a(0,0)*4096); + + +// Function: hashmap() +// Topics: Function Literals, Data Structures, Hashing +// Usage: Creating an Empty HashMap. +// hm = hashmap(); +// Usage: Creating a Populated HashMap. +// hm = hashmap(items=KEYVAL_LIST, ); +// Usage: Adding an Entry +// hm2 = hm(key, val); +// Usage: Adding Multiple Entries +// hm2 = hm(additems=KEYVAL_LIST); +// Usage: Removing an Entry +// hm2 = hm(del=KEY); +// Usage: Fetching a Value +// x = hm(key); +// Usage: Iterating a HashMap +// for (kv=hm()) let(k=kv[0], v=kv[1]) ... +// Description: +// This is a factory function for creating hashmap data structure functions. You can use a hashmap +// to store large amounts of [key,value] data. At around 4000 items, this becomes faster than using +// `search()` through the list. +// Arguments: +// --- +// hashsize = The number of hashtable buckets to form. +// items = A list of [key,value] pairs to initialize the hashmap with. +// FunctionLiteral Args: +// k = The key name. +// v = The value to store with the key. +// --- +// del = If given the key of an item to delete, makes a new hashmap with that item removed. +// additems = If given a list of [key,val] pairs, makes a new hashmap with the items added. +// Example: +// hm = hashmap(items=[for (i=[0:9999]) [str("foo",i),i]]); +// a = hm("foo37"); // Returns: 37 +// hm2 = hm("Blah", 39); // Adds entry "Blah" with val 39. +// b = hm2("Blah"); // Returns: 39 +// hm3 = hm2(additems=[["bar",39],["qux",21]]); // Adds "bar" and "qux" +// hm4 = hm3(del="Blah"); // Deletes entry "Blah". +// for (kv = hm4()) { // Iterates over all key/value pairs. +// echo(key=kv[0], val=kv[1]); +// } +function hashmap(hashsize=127,items,table) = + let( + table = !is_undef(table)? table : [for (i=[0:1:hashsize-1]) []] + ) + items != undef? hashmap(hashsize=hashsize, table=table)(additems=items) : + function(k,v,del,additems) + additems!=undef? let( + hashes = [for (item = additems) simple_hash(item[0]) % hashsize], + grouped = list_pad(group_data(hashes, additems), hashsize, []), + table = [for (i=idx(table)) concat(table[i],grouped[i])] + ) hashmap(hashsize=hashsize, table=table) : + del!=undef? let( + bnum = simple_hash(del) % hashsize, + bucket = [for (item=table[bnum]) if (item[0]!=del) item], + table = [for (i=idx(table)) i==bnum? bucket : table[i]] + ) hashmap(hashsize=hashsize, table=table) : + k==undef && v==undef? [for (bucket=table, item=bucket) item] : + let( + bnum = simple_hash(k) % hashsize, + bucket = table[bnum], + fnd = search([k], bucket) + ) + k!=undef && v==undef? (fnd==[]? undef : bucket[fnd[0]][1]) : + let( + newtable = [ + for (i=idx(table)) + i!=bnum? table[i] : + !fnd? [[k,v], each bucket] : + [[k,v], for (j=idx(bucket)) if (j!=fnd[0]) bucket[i]] + ] + ) hashmap(hashsize=hashsize, table=newtable); + + + +////////////////////////////////////////////////////////////////////// +// Section: Function Meta-Generators + + +// Function: f_1arg() +// Topics: Function Literals, Function Literal Factories +// See Also: f_2arg(), f_3arg() +// Usage: +// fn = f_1arg(func); +// Description: +// Takes a function literal that accepts one argument, and returns a function +// literal factory that can be used to pre-fill out that argument with a constant. +// Example: +// f_str = f_1arg(function(a) str(a)); +// fn_str = f_str(); // = function(a) str(a); +// fn_str3 = f_str(3); // = function() str(3); +function f_1arg(func) = + function(a) + a==undef? func : + function() func(a); + + +// Function: f_2arg() +// Topics: Function Literals, Function Literal Factories +// See Also: f_1arg(), f_3arg() +// Usage: +// fn = f_2arg(func); +// Description: +// Takes a function literal that accepts two arguments, and returns a function +// literal factory that can be used to pre-fill out one or both of those arguments +// with a constant. +// Example: +// f_lt = f_2arg(function(a,b) a b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_cmp = f_cmp(); // = function(a,b) a==b?0: a>b?1: -1; +// fn_cmp3 = f_cmp(3); // = function(a) a==3?0: a>3?1: -1; +// fn_3cmp = f_cmp(a=3); // = function(b) 3==b?0: 3>b?1: -1; +// fn_3cmp4 = f_cmp(a=3,b=4); // = function() 3==4?0: 3>4?1: -1; +function f_cmp(a,b) = f_2arg(function (a,b) a==b?0: a>b?1: -1)(a,b); + + +// Function: f_gt() +// Usage: +// fn = f_gt(); +// fn = f_gt(a=); +// fn = f_gt(b=); +// fn = f_gt(a=,b=); +// Description: +// A factory that generates function literals based on `a > b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_gt = f_gt(); // = function(a,b) a>b; +// fn_gt3 = f_gt(3); // = function(a) a>3; +// fn_3gt = f_gt(a=3); // = function(b) 3>b; +// fn_3gt4 = f_gt(a=3,b=4); // = function() 3>4; +function f_gt(a,b) = f_2arg(function (a,b) a>b)(a,b); + + +// Function: f_lt() +// Usage: +// fn = f_lt(); +// fn = f_lt(a=); +// fn = f_lt(b=); +// fn = f_lt(a=,b=); +// Description: +// A factory that generates function literals based on `a < b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_lt = f_lt(); // = function(a,b) a= b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_gte = f_gte(); // = function(a,b) a>=b; +// fn_gte3 = f_gte(3); // = function(a) a>=3; +// fn_3gte = f_gte(a=3); // = function(b) 3>=b; +// fn_3gte4 = f_gte(a=3,b=4); // = function() 3>=4; +function f_gte(a,b) = f_2arg(function (a,b) a>=b)(a,b); + + +// Function: f_lte() +// Usage: +// fn = f_lte(); +// fn = f_lte(a=); +// fn = f_lte(b=); +// fn = f_lte(a=,b=); +// Description: +// A factory that generates function literals based on `a <= b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_lte = f_lte(); // = function(a,b) a<=b; +// fn_lte3 = f_lte(3); // = function(a) a<=3; +// fn_3lte = f_lte(a=3); // = function(b) 3<=b; +// fn_3lte4 = f_lte(a=3,b=4); // = function() 3<=4; +function f_lte(a,b) = f_2arg(function (a,b) a<=b)(a,b); + + +// Function: f_eq() +// Usage: +// fn = f_eq(); +// fn = f_eq(a=); +// fn = f_eq(b=); +// fn = f_eq(a=,b=); +// Description: +// A factory that generates function literals based on `a == b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_eq = f_eq(); // = function(a,b) a==b; +// fn_eq3 = f_eq(3); // = function(a) a==3; +// fn_3eq4 = f_eq(a=3,b=4); // = function() 3==4; +function f_eq(a,b) = f_2arg(function (a,b) a==b)(a,b); + + +// Function: f_neq() +// Usage: +// fn = f_neq(); +// fn = f_neq(a=); +// fn = f_neq(b=); +// fn = f_neq(a=,b=); +// Description: +// A factory that generates function literals based on `a != b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_neq = f_neq(); // = function(a,b) a!=b; +// fn_neq3 = f_neq(3); // = function(a) a!=3; +// fn_3neq4 = f_neq(a=3,b=4); // = function() 3!=4; +function f_neq(a,b) = f_2arg(function (a,b) a!=b)(a,b); + + +// Function: f_approx() +// Usage: +// fn = f_approx(); +// fn = f_approx(a=); +// fn = f_approx(b=); +// fn = f_approx(a=,b=); +// Description: +// A factory that generates function literals based on `approx(a,b)`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_approx = f_approx(); // = function(a,b) approx(a,b); +// fn_approx3 = f_approx(3); // = function(a) approx(a,3); +// fn_3approx = f_approx(a=3); // = function(b) approx(3,b); +// fn_3approx4 = f_approx(a=3,b=4); // = function() approx(3,4); +function f_approx(a,b) = f_2arg(function (a,b) approx(a,b))(a,b); + + +// Function: f_napprox() +// Usage: +// fn = f_napprox(); +// fn = f_napprox(a=); +// fn = f_napprox(b=); +// fn = f_napprox(a=,b=); +// Description: +// A factory that generates function literals based on `napprox(a,b)`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// Example: +// fn_napprox = f_napprox(); // = function(a,b) napprox(a,b); +// fn_napprox3 = f_napprox(3); // = function(a) napprox(a,3); +// fn_3napprox = f_napprox(a=3); // = function(b) napprox(3,b); +// fn_3napprox4 = f_napprox(a=3,b=4); // = function() napprox(3,4); +function f_napprox(a,b) = f_2arg(function (a,b) !approx(a,b))(a,b); + + + +////////////////////////////////////////////////////////////////////// +// Section: Logic Operators + + +// Function: f_or() +// Topics: Function Literals, Logic, Boolean Operations +// Usage: +// fn = f_or(); +// fn = f_or(a=); +// fn = f_or(b=); +// fn = f_or(a=,b=); +// Description: +// A factory that generates function literals based on `a || b`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not() +function f_or(a,b) = f_2arg(function(a,b) (a || b))(a,b); + + +// Function: f_and() +// Topics: Function Literals, Logic, Boolean Operations +// Usage: +// fn = f_and(); +// fn = f_and(a=); +// fn = f_and(b=); +// fn = f_and(a=,b=); +// Description: +// A factory that generates function literals based on `a && b`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not() +function f_and(a,b) = f_2arg(function(a,b) (a && b))(a,b); + + +// Function: f_nor() +// Topics: Function Literals, Logic, Boolean Operations +// Usage: +// fn = f_nor(); +// fn = f_nor(a=); +// fn = f_nor(b=); +// fn = f_nor(a=,b=); +// Description: +// A factory that generates function literals based on `!(a || b)`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not() +function f_nor(a,b) = f_2arg(function(a,b) !(a || b))(a,b); + + +// Function: f_nand() +// Topics: Function Literals, Logic, Boolean Operations +// Usage: +// fn = f_nand(); +// fn = f_nand(a=); +// fn = f_nand(b=); +// fn = f_nand(a=,b=); +// Description: +// A factory that generates function literals based on `!(a && b)`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not() +function f_nand(a,b) = f_2arg(function(a,b) !(a && b))(a,b); + + +// Function: f_xor() +// Topics: Function Literals, Logic, Boolean Operations +// Usage: +// fn = f_xor(); +// fn = f_xor(a=); +// fn = f_xor(b); +// fn = f_xor(a=,b=); +// Description: +// A factory that generates function literals based on `(!a && b) || (a && !b)`, where +// either or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not() +function f_xor(a,b) = f_2arg(function(a,b) (!a && b) || (a && !b))(a,b); + + +// Function: f_not() +// Topics: Function Literals, Logic, Boolean Operations +// Usage: +// fn = f_not(); +// fn = f_not(a); +// Description: +// A factory that generates function literals based on `!a`, where the `a` +// argument can be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not() +function f_not(a) = f_1arg(function(a) !a)(a); + + +// Function: f_even() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_even(); +// fn = f_even(a); +// Description: +// A factory that generates function literals based on `a % 2 == 0`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not(), f_even(), f_odd() +// Example: +// l2 = filter(f_even(), [3,4,5,6,7,8]); // Returns: [4,6,8] +function f_even(a) = f_1arg(function(a) a % 2 == 0)(a); + + +// Function: f_odd() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_odd(); +// fn = f_odd(a); +// Description: +// A factory that generates function literals based on `a % 2 != 0`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_or(), f_and(), f_nor(), f_nand(), f_xor(), f_not(), f_even(), f_odd() +// Example: +// l2 = filter(f_odd(), [3,4,5,6,7,8]); // Returns: [3,5,7] +function f_odd(a) = f_1arg(function(a) a % 2 != 0)(a); + + + +////////////////////////////////////////////////////////////////////// +// Section: Math Operators + + +// Function: f_add() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_add(); +// fn = f_add(a=); +// fn = f_add(b); +// fn = f_add(a=,b=); +// Description: +// A factory that generates function literals based on `a + b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_add(a,b) = f_2arg(function(a,b) a + b)(a,b); + + +// Function: f_sub() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_sub(); +// fn = f_sub(a=); +// fn = f_sub(b); +// fn = f_sub(a=,b=); +// Description: +// A factory that generates function literals based on `a - b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_sub(a,b) = f_2arg(function(a,b) a - b)(a,b); + + +// Function: f_mul() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_mul(); +// fn = f_mul(a=); +// fn = f_mul(b); +// fn = f_mul(a=,b=); +// Description: +// A factory that generates function literals based on `a * b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_mul(a,b) = f_2arg(function(a,b) a * b)(a,b); + + +// Function: f_div() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_div(); +// fn = f_div(a=); +// fn = f_div(b); +// fn = f_div(a=,b=); +// Description: +// A factory that generates function literals based on `a / b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_div(a,b) = f_2arg(function(a,b) a / b)(a,b); + + +// Function: f_mod() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_mod(); +// fn = f_mod(a=); +// fn = f_mod(b); +// fn = f_mod(a=,b=); +// Description: +// A factory that generates function literals based on `a % b`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_mod(a,b) = f_2arg(function(a,b) a % b)(a,b); + + +// Function: f_pow() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_pow(); +// fn = f_pow(a=); +// fn = f_pow(b); +// fn = f_pow(a=,b=); +// Description: +// A factory that generates function literals based on `pow(a,b)`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_pow(a,b) = f_2arg(function(a,b) pow(a,b))(a,b); + + +// Function: f_neg() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_neg(); +// fn = f_neg(a); +// Description: +// A factory that generates function literals based on `-a`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_add(), f_sub(), f_mul(), f_div(), f_mod(), f_pow(), f_neg() +function f_neg(a) = f_1arg(function(a) -a)(a); + + + +////////////////////////////////////////////////////////////////////// +// Section: Min/Max Operators + + +// Function: f_min() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_min(); +// fn = f_min(a); +// Description: +// A factory that generates function literals based on `min(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_min(), f_max(), f_min2(), f_max2(), f_min3(), f_max3() +function f_min(a) = f_1arg(function(a) min(a))(a); + + +// Function: f_max() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_max(); +// fn = f_max(a); +// Description: +// A factory that generates function literals based on `max(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_min(), f_max(), f_min2(), f_max2(), f_min3(), f_max3() +function f_max(a) = f_1arg(function(a) max(a))(a); + + +// Function: f_min2() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_min2(); +// fn = f_min2(a=); +// fn = f_min2(b); +// fn = f_min2(a=,b=); +// Description: +// A factory that generates function literals based on `min(a,b)`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_min(), f_max(), f_min2(), f_max2(), f_min3(), f_max3() +function f_min2(a,b) = f_2arg(function(a,b) min(a,b))(a,b); + + +// Function: f_max2() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_max2(); +// fn = f_max2(a=); +// fn = f_max2(b); +// fn = f_max2(a=,b=); +// Description: +// A factory that generates function literals based on `max(a,b)`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_min(), f_max(), f_min2(), f_max2(), f_min3(), f_max3() +function f_max2(a,b) = f_2arg(function(a,b) max(a,b))(a,b); + + +// Function: f_min3() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_min3(); +// fn = f_min3(a=); +// fn = f_min3(b=); +// fn = f_min3(c=); +// fn = f_min3(a=,b=); +// fn = f_min3(b=,c=); +// fn = f_min3(a=,c=); +// fn = f_min3(a=,b=,c=); +// Description: +// A factory that generates function literals based on `min(a,b,c)`, where any +// or all of the `a`, `b`, or`c` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// c = If given, replaces the third argument. +// See Also: f_min(), f_max(), f_min2(), f_max2(), f_min3(), f_max3() +function f_min3(a,b,c) = f_3arg(function(a,b,c) min(a,b,c))(a,b,c); + + +// Function: f_max3() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_max3(); +// fn = f_max3(a=); +// fn = f_max3(b=); +// fn = f_max3(c=); +// fn = f_max3(a=,b=); +// fn = f_max3(b=,c=); +// fn = f_max3(a=,c=); +// fn = f_max3(a=,b=,c=); +// Description: +// A factory that generates function literals based on `min(a,b,c)`, where any +// or all of the `a`, `b`, or`c` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// c = If given, replaces the third argument. +// See Also: f_min(), f_max(), f_min2(), f_max2(), f_min3(), f_max3() +function f_max3(a,b,c) = f_3arg(function(a,b,c) max(a,b,c))(a,b,c); + + + +////////////////////////////////////////////////////////////////////// +// Section: Trigonometry Operators + + +// Function: f_sin() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_sin(); +// fn = f_sin(a); +// Description: +// A factory that generates function literals based on `sin(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_sin(a) = f_1arg(function(a) sin(a))(a); + + +// Function: f_cos() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_cos(); +// fn = f_cos(a); +// Description: +// A factory that generates function literals based on `cos(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_cos(a) = f_1arg(function(a) cos(a))(a); + + +// Function: f_tan() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_tan(); +// fn = f_tan(a); +// Description: +// A factory that generates function literals based on `tan(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_tan(a) = f_1arg(function(a) tan(a))(a); + + +// Function: f_asin() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_asin(); +// fn = f_asin(a); +// Description: +// A factory that generates function literals based on `asin(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_asin(a) = f_1arg(function(a) asin(a))(a); + + +// Function: f_acos() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_acos(); +// fn = f_acos(a); +// Description: +// A factory that generates function literals based on `acos(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_acos(a) = f_1arg(function(a) acos(a))(a); + + +// Function: f_atan() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_atan(); +// fn = f_atan(a); +// Description: +// A factory that generates function literals based on `atan(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_atan(a) = f_1arg(function(a) atan(a))(a); + + +// Function: f_atan2() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_atan2(); +// fn = f_atan2(a=); +// fn = f_atan2(b); +// fn = f_atan2(a=,b=); +// Description: +// A factory that generates function literals based on `atan2(a,b)`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_sin(), f_cos(), f_tan(), f_asin(), f_acos(), f_atan(), f_atan2() +function f_atan2(a,b) = f_2arg(function(a,b) atan2(a,b))(a,b); + + + +////////////////////////////////////////////////////////////////////// +// Section: String Operators + + +// Function: f_len() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_len(); +// fn = f_len(a); +// Description: +// A factory that generates function literals based on `len(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_len(), f_chr(), f_ord(), f_str(), f_str2(), f_str3() +function f_len(a) = f_1arg(function(a) len(a))(a); + + +// Function: f_chr() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_chr(); +// fn = f_chr(a); +// Description: +// A factory that generates function literals based on `chr(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_len(), f_chr(), f_ord(), f_str(), f_str2(), f_str3() +function f_chr(a) = f_1arg(function(a) chr(a))(a); + + +// Function: f_ord() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_ord(); +// fn = f_ord(a); +// Description: +// A factory that generates function literals based on `ord(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_len(), f_chr(), f_ord(), f_str(), f_str2(), f_str3() +function f_ord(a) = f_1arg(function(a) ord(a))(a); + + +// Function: f_str() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_str(); +// fn = f_str(a); +// Description: +// A factory that generates function literals based on `str(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_len(), f_chr(), f_ord(), f_str(), f_str2(), f_str3() +function f_str(a) = f_1arg(function(a) str(a))(a); + + +// Function: f_str2() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_str2(); +// fn = f_str2(a=); +// fn = f_str2(b); +// fn = f_str2(a=,b=); +// Description: +// A factory that generates function literals based on `str(a,b)`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_len(), f_chr(), f_ord(), f_str(), f_str2(), f_str3() +function f_str2(a,b) = f_2arg(function(a,b) str(a,b))(a,b); + + +// Function: f_str3() +// Topics: Function Literals, Math Operators +// Usage: +// fn = f_str3(); +// fn = f_str3(a=); +// fn = f_str3(b=); +// fn = f_str3(c=); +// fn = f_str3(a=,b=); +// fn = f_str3(b=,c=); +// fn = f_str3(a=,c=); +// fn = f_str3(a=,b=,c=); +// Description: +// A factory that generates function literals based on `str(a,b,c)`, where any +// or all of the `a`, `b`, or`c` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// c = If given, replaces the third argument. +// See Also: f_len(), f_chr(), f_ord(), f_str(), f_str2(), f_str3() +function f_str3(a,b,c) = f_3arg(function(a,b,c) str(a,b,c))(a,b,c); + + + +////////////////////////////////////////////////////////////////////// +// Section: Miscellaneous Operators + + +// Function: f_floor() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_floor(); +// fn = f_floor(a); +// Description: +// A factory that generates function literals based on `floor(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_floor(), f_ceil(), f_round() +function f_floor(a) = f_1arg(function(a) floor(a))(a); + + +// Function: f_round() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_round(); +// fn = f_round(a); +// Description: +// A factory that generates function literals based on `round(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_floor(), f_ceil(), f_round() +function f_round(a) = f_1arg(function(a) round(a))(a); + + +// Function: f_ceil() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_ceil(); +// fn = f_ceil(a); +// Description: +// A factory that generates function literals based on `ceil(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_floor(), f_ceil(), f_round() +function f_ceil(a) = f_1arg(function(a) ceil(a))(a); + + +// Function: f_abs() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_abs(); +// fn = f_abs(a); +// Description: +// A factory that generates function literals based on `abs(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_abs(a) = f_1arg(function(a) abs(a))(a); + + +// Function: f_sign() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_sign(); +// fn = f_sign(a); +// Description: +// A factory that generates function literals based on `sign(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_sign(a) = f_1arg(function(a) sign(a))(a); + + +// Function: f_ln() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_ln(); +// fn = f_ln(a); +// Description: +// A factory that generates function literals based on `ln(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_ln(a) = f_1arg(function(a) ln(a))(a); + + +// Function: f_log() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_log(); +// fn = f_log(a); +// Description: +// A factory that generates function literals based on `log(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_log(a) = f_1arg(function(a) log(a))(a); + + +// Function: f_exp() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_exp(); +// fn = f_exp(a); +// Description: +// A factory that generates function literals based on `exp(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_exp(a) = f_1arg(function(a) exp(a))(a); + + +// Function: f_sqr() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_sqr(); +// fn = f_sqr(a); +// Description: +// A factory that generates function literals based on `a*a`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_sqr(a) = f_1arg(function(a) a*a)(a); + + +// Function: f_sqrt() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_sqrt(); +// fn = f_sqrt(a); +// Description: +// A factory that generates function literals based on `sqrt(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_sqrt(a) = f_1arg(function(a) sqrt(a))(a); + + +// Function: f_norm() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_norm(); +// fn = f_norm(a); +// Description: +// A factory that generates function literals based on `norm(a)`, where the `a` +// argument can optionally be replaced with a constant. +// Arguments: +// a = If given, replaces the argument. +// See Also: f_abs(), f_sign(), f_ln(), f_log(), f_exp(), f_sqr(), f_sqrt() +function f_norm(a) = f_1arg(function(a) norm(a))(a); + + +// Function: f_cross() +// Topics: Function Literals, String Operators +// Usage: +// fn = f_cross(); +// fn = f_cross(a=); +// fn = f_cross(b); +// fn = f_cross(a=,b=); +// Description: +// A factory that generates function literals based on `str(a,b)`, where either +// or both of the `a` or `b` arguments can be replaced with constants. +// Arguments: +// a = If given, replaces the first argument. +// b = If given, replaces the second argument. +// See Also: f_norm(), f_abs(), f_sign(), f_cross() +function f_cross(a,b) = f_2arg(function(a,b) cross(a,b))(a,b); + + +// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/hull.scad b/hull.scad index a7b73c70..6961e1a8 100644 --- a/hull.scad +++ b/hull.scad @@ -158,7 +158,7 @@ function _hull_collinear(points) = // %polyhedron(points=pts, faces=faces); function hull3d_faces(points) = assert(is_path(points,3),"Invalid input to hull3d_faces") - len(points) < 3 ? range(len(points)) + len(points) < 3 ? count(len(points)) : let ( // start with a single non-collinear triangle tri = noncollinear_triple(points, error=false) ) diff --git a/math.scad b/math.scad index 9e4f73a7..43b13479 100644 --- a/math.scad +++ b/math.scad @@ -494,7 +494,7 @@ function rand_int(minval, maxval, N, seed=undef) = function gaussian_rands(mean, stddev, N=1, seed=undef) = assert( is_finite(mean+stddev+N) && (is_undef(seed) || is_finite(seed) ), "Input must be finite numbers.") let(nums = is_undef(seed)? rands(0,1,N*2) : rands(0,1,N*2,seed)) - [for (i = range(N)) mean + stddev*sqrt(-2*ln(nums[i*2]))*cos(360*nums[i*2+1])]; + [for (i = count(N,0,2)) mean + stddev*sqrt(-2*ln(nums[i]))*cos(360*nums[i+1])]; // Function: log_rands() diff --git a/paths.scad b/paths.scad index 6db525aa..74f999e3 100644 --- a/paths.scad +++ b/paths.scad @@ -1240,18 +1240,15 @@ module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=fals length = path_length(path,closed); distances = is_def(sp)? ( // Start point given - is_def(n) && is_def(spacing)? range(s=sp, step=spacing, n=n) : - is_def(n)? range(s=sp, e=length, n=n) : - range(s=sp, step=spacing, e=length) - ) - : is_def(n) && is_undef(spacing)? ( // N alone given - closed ? rangex(s=0, e=length, n=n) - : range(s=0, e=length, n=n) + is_def(n) && is_def(spacing)? count(n,sp,spacing) : + is_def(n)? lerpn(sp, length, n) : + list([sp:spacing:length]) ) + : is_def(n) && is_undef(spacing)? lerpn(0,length,n,!closed) // N alone given : ( // No start point and spacing is given, N maybe given let( n = is_def(n)? n : floor(length/spacing)+(closed?0:1), - ptlist = range(s=0,step=spacing,n=n), + ptlist = count(n,0,spacing), listcenter = mean(ptlist) ) closed? sort([for(entry=ptlist) posmod(entry-listcenter,length)]) : @@ -1607,7 +1604,7 @@ function resample_path(path, N, spacing, closed=false) = // path_cut to return the endpoint (which might fail due to rounding) // Add last point later N = is_def(N) ? N-(closed?0:1) : round(length/spacing), - distlist = rangex(N,e=length), + distlist = lerpn(0,length,N,false), cuts = path_cut_points(path, distlist, closed=closed) ) [ each subindex(cuts,0), diff --git a/regions.scad b/regions.scad index b76785c3..b42b29ec 100644 --- a/regions.scad +++ b/regions.scad @@ -438,7 +438,7 @@ function linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg path = is_undef(maxseg)? p : [ 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]) + lerpn(seg.x, seg.y, steps, false) ] ) rot(twist, p=scale([scale,scale],p=path)) @@ -451,7 +451,7 @@ function linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg path = is_undef(maxseg)? p : [ 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]) + lerpn(seg.x, seg.y, steps, false) ], verts = [ for (i=[0:1:slices]) let( diff --git a/rounding.scad b/rounding.scad index 815e220c..b85a70cb 100644 --- a/rounding.scad +++ b/rounding.scad @@ -194,7 +194,7 @@ include // square = [[0,0],[1,0],[1,1],[0,1]]; // spiral = flatten(repeat(concat(square,reverse(square)),5)); // Squares repeat 10 times, forward and backward // squareind = [for(i=[0:9]) each [i,i,i,i]]; // Index of the square for each point -// z = range(40)*.2+squareind; +// z = count(40)*.2+squareind; // path3d = hstack(spiral,z); // 3D spiral // rounding = squareind/20; // // Setting k=1 means curvature won't be continuous, but curves are as round as possible @@ -899,7 +899,7 @@ function _make_offset_polyhedron(path,offsets, offset_type, flip_faces, quality, vertexcount=0, vertices=[], faces=[] )= offsetind==len(offsets)? ( let( - bottom = range(n=len(path),s=vertexcount), + bottom = count(len(path),vertexcount), oriented_bottom = !flip_faces? bottom : reverse(bottom) ) [vertices, concat(faces,[oriented_bottom])] ) : ( @@ -1956,7 +1956,7 @@ function bezier_patch_degenerate(patch, splinesteps=16, reverse=false) = bot_degen = last(patch)[0] == last(last(patch)), left_degen = patch[0][0] == last(patch)[0], right_degen = last(patch[0]) == last(last(patch)), - samplepts = range(splinesteps+1)/splinesteps + samplepts = count(splinesteps+1)/splinesteps ) top_degen && bot_degen && left_degen && right_degen ? // fully degenerate case [repeat([patch[0][0]],4), EMPTY_VNF] : @@ -1990,13 +1990,13 @@ function bezier_patch_degenerate(patch, splinesteps=16, reverse=false) = // at this point top_degen is true // only top is degenerate let( full_degen = patch[1][0] == last(patch[1]), - rowmax = full_degen ? range(splinesteps+1) : + rowmax = full_degen ? count(splinesteps+1) : [for(j=[0:splinesteps]) j<=splinesteps/2 ? 2*j : splinesteps], vbb=echo("single degenerate case"), bpatch = [for(i=[0:1:len(patch[0])-1]) bezier_points(subindex(patch,i), samplepts)], pts = [ [bpatch[0][0]], - for(j=[1:splinesteps]) bezier_points(subindex(bpatch,j), range(rowmax[j]+1)/rowmax[j]) + for(j=[1:splinesteps]) bezier_points(subindex(bpatch,j), lerpn(0,1,rowmax[j]+1)) ], vnf = vnf_tri_array(pts, reverse=reverse) ) [ diff --git a/screws.scad b/screws.scad index 1ce6ec0f..b66674d6 100644 --- a/screws.scad +++ b/screws.scad @@ -1085,7 +1085,7 @@ function _ISO_thread_tolerance(diameter, pitch, internal=false, tolerance=undef) ], rangepts = [0.99, 1.4, 2.8, 5.6, 11.2, 22.4, 45, 90, 180, 300], - d_ind = floor(lookup(diameter,hstack(rangepts,range(len(rangepts))))), + d_ind = floor(lookup(diameter,hstack(rangepts,count(len(rangepts))))), avgd = sqrt(rangepts[d_ind]* rangepts[d_ind+1]), T_d2_6 = 90*pow(P, 0.4)*pow(avgd,0.1), diff --git a/skin.scad b/skin.scad index 8275c514..cf75796f 100644 --- a/skin.scad +++ b/skin.scad @@ -595,7 +595,7 @@ function subdivide_long_segments(path, maxlen, closed=false) = [ for (p=pair(path,closed)) let( steps = ceil(norm(p[1]-p[0])/maxlen) - ) each lerp(p[0],p[1],[0:1/steps:1-EPSILON]), + ) each lerpn(p[0], p[1], steps, false), if (!closed) last(path) ]; @@ -620,7 +620,7 @@ function slice_profiles(profiles,slices,closed=false) = let( count = is_num(slices) ? repeat(slices,len(profiles)-(closed?0:1)) : slices, slicelist = [for (i=[0:len(profiles)-(closed?1:2)]) - each [for(j = [0:count[i]]) lerp(profiles[i],select(profiles,i+1),j/(count[i]+1))] + each lerpn(profiles[i], select(profiles,i+1), count[i]+1, false) ] ) concat(slicelist, closed?[]:[profiles[len(profiles)-1]]); @@ -894,7 +894,7 @@ function associate_vertices(polygons, split, curpoly=0) = str("Split ",cursplit," at polygon ",curpoly," has invalid vertices. Must be in [0:",polylen-1,"]")) len(cursplit)==0 ? associate_vertices(polygons,split,curpoly+1) : let( - splitindex = sort(concat(range(polylen), cursplit)), + splitindex = sort(concat(count(polylen), cursplit)), newpoly = [for(i=[0:len(polygons)-1]) i<=curpoly ? select(polygons[i],splitindex) : polygons[i]] ) associate_vertices(newpoly, split, curpoly+1); diff --git a/strings.scad b/strings.scad index 147d5581..1577aee7 100644 --- a/strings.scad +++ b/strings.scad @@ -335,7 +335,7 @@ function _str_find_last(str,pattern,sindex) = (sindex >=0 ? sindex : undef); function _str_find_all(str,pattern) = - pattern == "" ? range(len(str)) : + pattern == "" ? count(len(str)) : [for(i=[0:1:len(str)-len(pattern)]) if (_str_cmp(str,i,pattern)) i]; diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index 679f34c6..8569d7f6 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -133,36 +133,13 @@ module test_repeat() { test_repeat(); -module test_range() { - assert(range(4) == [0,1,2,3]); - assert(range(n=4, step=2) == [0,2,4,6]); - assert(range(n=4, s=3, step=3) == [3,6,9,12]); - assert(range(e=3) == [0,1,2,3]); - assert(range(e=6, step=2) == [0,2,4,6]); - assert(range(s=3, e=5) == [3,4,5]); - assert(range(s=3, e=8, step=2) == [3,5,7]); - assert(range(s=4, e=8, step=2) == [4,6,8]); - assert(range(e=4, n=3) == [0,2,4]); - assert(range(n=4, s=[3,4], step=[2,3]) == [[3,4], [5,7], [7,10], [9,13]]); +module test_count() { + assert_equal(count(5), [0,1,2,3,4]); + assert_equal(count(5,3), [3,4,5,6,7]); + assert_equal(count(4,3,2), [3,5,7,9]); + assert_equal(count(5,0,0.25), [0, 0.25, 0.5, 0.75, 1.0]); } -test_range(); - - -module test_rangex() { - assert_equal(rangex(4), [0,1,2,3]); - assert_approx(rangex(5,e=1), [0, 0.2, 0.4, 0.6, 0.8]); - assert_equal(rangex(n=4, step=2), [0,2,4,6]); - assert_approx(rangex(n=4, step=0.25), [0,0.25,0.5,0.75]); - assert_equal(rangex(n=4, s=3, step=3), [3,6,9,12]); - assert_equal(rangex(e=3), [0,1,2]); - assert_equal(rangex(e=6, step=2), [0,2,4]); - assert_equal(rangex(s=3, e=5), [3,4]); - assert_equal(rangex(s=3, e=8, step=2), [3,5,7]); - assert_equal(rangex(s=4, e=8, step=2), [4,6]); - assert_equal(rangex(e=6, n=3), [0,2,4]); - assert_equal(rangex(n=4, s=[3,4], step=[2,3]), [[3,4], [5,7], [7,10], [9,13]]); -} -test_rangex(); +test_count(); module test_reverse() { @@ -322,7 +299,7 @@ test_enumerate(); module test_shuffle() { - nums1 = [for (i=range(100)) i]; + nums1 = count(100); nums2 = shuffle(nums1,33); nums3 = shuffle(nums2,99); assert(sort(nums2)==nums1); diff --git a/tests/test_geometry.scad b/tests/test_geometry.scad index 492deb14..6fe00c12 100644 --- a/tests/test_geometry.scad +++ b/tests/test_geometry.scad @@ -481,7 +481,7 @@ module test_circle_3points() { radii = rands(10,100,count,seed_value=390); angles = rands(0,360,count,seed_value=699); // 2D tests. - for(i = range(count)) { + for(i = count(count)) { cp = select(coords,i,i+1); r = radii[i]; angs = sort(select(angles,i,i+2)); @@ -506,7 +506,7 @@ module test_circle_3points() { assert(approx(res[2], UP)); } } - for(i = range(count)) { + for(i = count(count)) { cp = select(coords,i,i+1); r = radii[i]; angs = sort(select(angles,i,i+2)); @@ -532,7 +532,7 @@ module test_circle_3points() { } } // 3D tests. - for(i = range(count)) { + for(i = count(count)) { cp = select(coords,i,i+2); r = radii[i]; nrm = unit(select(coords,i+10,i+12)); @@ -559,7 +559,7 @@ module test_circle_3points() { assert(approx(res[2], n)); } } - for(i = range(count)) { + for(i = count(count)) { cp = select(coords,i,i+2); r = radii[i]; nrm = unit(select(coords,i+10,i+12)); @@ -988,8 +988,8 @@ module test_pointlist_bounds() { module test_closest_point() { - ptlist = [for (i=range(100)) rands(-100,100,2,seed_value=8463)]; - testpts = [for (i=range(100)) rands(-100,100,2,seed_value=6834)]; + ptlist = [for (i=count(100)) rands(-100,100,2,seed_value=8463+i)]; + testpts = [for (i=count(100)) rands(-100,100,2,seed_value=6834+i)]; for (pt = testpts) { pidx = closest_point(pt,ptlist); dists = [for (p=ptlist) norm(pt-p)]; @@ -1001,8 +1001,8 @@ module test_closest_point() { module test_furthest_point() { - ptlist = [for (i=range(100)) rands(-100,100,2,seed_value=8463)]; - testpts = [for (i=range(100)) rands(-100,100,2,seed_value=6834)]; + ptlist = [for (i=count(100)) rands(-100,100,2,seed_value=8463+i)]; + testpts = [for (i=count(100)) rands(-100,100,2,seed_value=6834+i)]; for (pt = testpts) { pidx = furthest_point(pt,ptlist); dists = [for (p=ptlist) norm(pt-p)]; diff --git a/tests/test_math.scad b/tests/test_math.scad index 8dfdb9d2..025dde7d 100644 --- a/tests/test_math.scad +++ b/tests/test_math.scad @@ -1133,7 +1133,7 @@ module test_real_roots(){ // Wilkinson polynomial is a nasty test: assert_approx( sort(real_roots(poly_mult([[1,-1],[1,-2],[1,-3],[1,-4],[1,-5],[1,-6],[1,-7],[1,-8],[1,-9],[1,-10]]))), - range(n=10,s=1)); + count(10,1)); assert_equal(real_roots([3]), []); assert_equal(real_roots(poly_mult([[1,-2,5],[12,-24,24],[-2, -12, -20],[1,-10,50]])),[]); assert_equal(real_roots(poly_mult([[1,-2,5],[12,-24,24],[-2, -12, -20],[1,-10,50],[1,0,0]])),[0,0]);