mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 00:09:41 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
c98dc64d20
5 changed files with 339 additions and 305 deletions
315
fnliterals.scad
315
fnliterals.scad
|
@ -48,7 +48,7 @@ function map(func, list) =
|
|||
// Topics: Function Literals, Looping, Filters
|
||||
// Usage:
|
||||
// lst = filter(func, list);
|
||||
// lst = filter(function (x) x+1, 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:
|
||||
|
@ -235,35 +235,72 @@ function for_n(n,init,func) =
|
|||
a(init, n[0]);
|
||||
|
||||
|
||||
// Function: find_all()
|
||||
// Topics: Function Literals, Looping, Filters
|
||||
// Usage:
|
||||
// indices = find_all(func, list);
|
||||
// indices = find_all(function (x) x>1, list);
|
||||
// Description:
|
||||
// Returns the indices of all items in `list` that the function `func` returns true for.
|
||||
// In pseudo-code, this is effectively:
|
||||
// ```
|
||||
// function find_all(func,list):
|
||||
// out = [];
|
||||
// foreach item in list:
|
||||
// if func(item) is true:
|
||||
// append item index 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: find_all(), map(), reduce(), accumulate(), while(), for_n()
|
||||
// Example:
|
||||
// func = function(x) x>5;
|
||||
// echo(find_all(func, [3,4,5,6,7]));
|
||||
// // ECHO: [3,4]
|
||||
function find_all(func, list) =
|
||||
assert(is_function(func))
|
||||
assert(is_list(list))
|
||||
[for (indexnum=idx(list)) if (func(list[indexnum])) indexnum];
|
||||
|
||||
|
||||
// Function: find_first()
|
||||
// Topics: Function Literals, Searching
|
||||
// Usage:
|
||||
// idx = find_first(val, list, [start=], [func=]);
|
||||
// idx = find_first(func, list, [start=]);
|
||||
// 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 (val,x)`, 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()
|
||||
// Finds the first item in `list`, after index `start`, which the function literal in `func` will return true for.
|
||||
// The signature of the function literal in `func` is `function (x)`, and it is expected to return true when the
|
||||
// value compares as matching. It should return false otherwise. If you need to find *all* matching items in the
|
||||
// list, you should use {{find_all()}} instead.
|
||||
// See Also: find_all(), map(), filter(), reduce(), accumulate(), while(), for_n(), binsearch()
|
||||
// Arguments:
|
||||
// val = The value to look for.
|
||||
// func = The function literal to use to check each item in `list`. Expects the signature `function (x)`, and a boolean return value.
|
||||
// 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()) =
|
||||
// Example:
|
||||
// data = [8,5,3,7,4,2,9];
|
||||
// echo(find_first(f_lte(4), data));
|
||||
// // ECHO: 2
|
||||
// Example:
|
||||
// data = [8,5,3,7,4,2,9];
|
||||
// echo(find_first(f_lte(4), data, start=3));
|
||||
// // ECHO: 4
|
||||
function find_first(func, list, start=0) =
|
||||
assert(is_function(func))
|
||||
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)
|
||||
listlen = len(list),
|
||||
_find_first = function(indexnum) (
|
||||
indexnum >= listlen? undef :
|
||||
func(list[indexnum])? indexnum :
|
||||
_find_first(indexnum+1)
|
||||
)
|
||||
)
|
||||
a(start);
|
||||
_find_first(start);
|
||||
|
||||
|
||||
// Function: binsearch()
|
||||
|
@ -287,7 +324,7 @@ function find_first(val, list, start=0, func=f_approx()) =
|
|||
// 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);
|
||||
// idx = binsearch("G", items, idx=0);
|
||||
function binsearch(key, list, idx, cmp=f_cmp()) =
|
||||
let(
|
||||
a = function(s,e)
|
||||
|
@ -417,17 +454,17 @@ function hashmap(hashsize=127,items,table) =
|
|||
// 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 f_1arg(target_func) =
|
||||
function(a)
|
||||
a==undef? function(x) func(x) :
|
||||
function() func(a);
|
||||
a==undef? function(x) target_func(x) :
|
||||
function() target_func(a);
|
||||
|
||||
|
||||
// Function: f_2arg()
|
||||
// Topics: Function Literals, Function Literal Factories
|
||||
// See Also: f_1arg(), f_3arg()
|
||||
// Usage:
|
||||
// fn = f_2arg(func);
|
||||
// fn = f_2arg(target_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
|
||||
|
@ -439,22 +476,44 @@ function f_1arg(func) =
|
|||
// fn_3lt = f_lt(a=3); // = function(b) 3<b;
|
||||
// fn_lt3 = f_lt(b=3); // = function(a) a<3;
|
||||
// fn_3lt4 = f_lt(3,4); // = function() 3<4;
|
||||
function f_2arg(func) =
|
||||
function f_2arg(target_func) =
|
||||
function(a,b)
|
||||
a==undef && b==undef? function(x,y) func(x,y) :
|
||||
a==undef? function(x) func(x,b) :
|
||||
b==undef? function(x) func(a,x) :
|
||||
function() func(a,b);
|
||||
a==undef && b==undef? function(x,y) target_func(x,y) :
|
||||
a==undef? function(x) target_func(x,b) :
|
||||
b==undef? function(x) target_func(a,x) :
|
||||
function() target_func(a,b);
|
||||
|
||||
|
||||
// Function: f_2arg_simple()
|
||||
// Topics: Function Literals, Function Literal Factories
|
||||
// See Also: f_1arg(), f_3arg()
|
||||
// Usage:
|
||||
// fn = f_2arg_simple(target_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. When given a single argument, fills out the segond function
|
||||
// argument with a constant.
|
||||
// Example:
|
||||
// f_lt = f_2arg_simple(function(a,b) a<b);
|
||||
// fn_lt = f_lt(); // = function(a,b) a<b;
|
||||
// fn_lt3 = f_lt(3); // = function(a) a<3;
|
||||
// fn_3lt4 = f_lt(3,4); // = function() 3<4;
|
||||
function f_2arg_simple(target_func) =
|
||||
function(a,b)
|
||||
a==undef && b==undef? function(x,y) target_func(x,y) :
|
||||
b==undef? function(x) target_func(x,a) :
|
||||
function() target_func(a,b);
|
||||
|
||||
|
||||
// Function: f_3arg()
|
||||
// Topics: Function Literals, Function Literal Factories
|
||||
// See Also: f_1arg(), f_2arg()
|
||||
// Usage:
|
||||
// fn = f_3arg(func);
|
||||
// fn = f_3arg(target_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
|
||||
// Takes a function literal that accepts three arguments, and returns a function
|
||||
// literal factory that can be used to pre-fill out some or all of those arguments
|
||||
// with a constant.
|
||||
// Example:
|
||||
// p1 = [10,4]; p2 = [3,7];
|
||||
|
@ -463,16 +522,16 @@ function f_2arg(func) =
|
|||
// fn_va2 = f_lt(c=p1); // = function(a,b) vector_angle(a,b,p1);
|
||||
// fn_va3 = f_lt(a=p2); // = function(a,c) vector_angle(a,p2,c);
|
||||
// fn_va4 = f_lt(a=p1,c=p2); // = function() vector_angle(p1,b,p2);
|
||||
function f_3arg(func) =
|
||||
function f_3arg(target_func) =
|
||||
function(a,b,c)
|
||||
a==undef && b==undef && c==undef? function(x,y,z) func(x,y,z) :
|
||||
a==undef && b==undef? function(x,y) func(x,y,c) :
|
||||
a==undef && c==undef? function(x,y) func(x,b,y) :
|
||||
b==undef && c==undef? function(x,y) func(a,x,y) :
|
||||
a==undef? function(x) func(x,b,c) :
|
||||
b==undef? function(x) func(a,x,c) :
|
||||
c==undef? function(x) func(a,b,x) :
|
||||
function() func(a,b,c);
|
||||
a==undef && b==undef && c==undef? function(x,y,z) target_func(x,y,z) :
|
||||
a==undef && b==undef? function(x,y) target_func(x,y,c) :
|
||||
a==undef && c==undef? function(x,y) target_func(x,b,y) :
|
||||
b==undef && c==undef? function(x,y) target_func(a,x,y) :
|
||||
a==undef? function(x) target_func(x,b,c) :
|
||||
b==undef? function(x) target_func(a,x,c) :
|
||||
c==undef? function(x) target_func(a,b,x) :
|
||||
function() target_func(a,b,c);
|
||||
|
||||
|
||||
// Function: ival()
|
||||
|
@ -482,13 +541,13 @@ function f_3arg(func) =
|
|||
// Wraps a single-argument function literal so that it can take two arguments,
|
||||
// passing the first argument along to the wrapped function.
|
||||
// Arguments:
|
||||
// func = The function of signature (x) to wrap.
|
||||
// target_func = The function of signature (x) to wrap.
|
||||
// FunctionLiteral Args:
|
||||
// a = The argument that will be passed through.
|
||||
// b = The argumen that will be discarded.
|
||||
// Example:
|
||||
// x = while(0, ival(f_lt(5)), xval(fngen_add(1)));
|
||||
function ival(func) = function(a,b) func(a);
|
||||
function ival(target_func) = function(a,b) target_func(a);
|
||||
|
||||
|
||||
// Function: xval()
|
||||
|
@ -498,13 +557,13 @@ function ival(func) = function(a,b) func(a);
|
|||
// Wraps a single-argument function literal so that it can take two arguments,
|
||||
// passing the first argument along to the wrapped function.
|
||||
// Arguments:
|
||||
// func = The function of signature (x) to wrap.
|
||||
// target_func = The function of signature (x) to wrap.
|
||||
// FunctionLiteral Args:
|
||||
// a = The argument that will be passed through.
|
||||
// b = The argumen that will be discarded.
|
||||
// Example:
|
||||
// x = while(0, ival(f_lt(5)), xval(fngen_add(1)));
|
||||
function xval(func) = function(a,b) func(b);
|
||||
function xval(target_func) = function(a,b) target_func(b);
|
||||
|
||||
|
||||
|
||||
|
@ -515,179 +574,137 @@ function xval(func) = function(a,b) func(b);
|
|||
// Function: f_cmp()
|
||||
// Usage:
|
||||
// fn = f_cmp();
|
||||
// fn = f_cmp(a=);
|
||||
// fn = f_cmp(b=);
|
||||
// fn = f_cmp(a=,b=);
|
||||
// fn = f_cmp(b);
|
||||
// fn = f_cmp(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.
|
||||
// A factory that generates function literals that compare `a` and `b`, where one or
|
||||
// both arguments can be replaced with constants. If `a` and `b` are equal, the function
|
||||
// literal will return 0. If a<b then -1 is returned. If a>b then 1 is returned.
|
||||
// Example:
|
||||
// fn_cmp = f_cmp(); // = function(a,b) a==b?0: a>b?1: -1;
|
||||
// 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);
|
||||
// fn_3cmp4 = f_cmp(3,4); // = function() 3==4?0: 3>4?1: -1;
|
||||
function f_cmp(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// A factory that generates function literals based on `a > b`, where one
|
||||
// or both of the arguments can be replaced with constants.
|
||||
// Example:
|
||||
// fn_gt = f_gt(); // = function(a,b) a>b;
|
||||
// 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);
|
||||
// fn_3gt4 = f_gt(3,4); // = function() 3>4;
|
||||
function f_gt(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// A factory that generates function literals based on `a < b`, where one
|
||||
// or both of the arguments can be replaced with constants.
|
||||
// Example:
|
||||
// fn_lt = f_lt(); // = function(a,b) a<b;
|
||||
// fn_lt = f_lt(); // = function(a,b) a<b;
|
||||
// fn_lt3 = f_lt(3); // = function(a) a<3;
|
||||
// fn_3lt = f_lt(a=3); // = function(b) 3<b;
|
||||
// fn_3lt4 = f_lt(a=3,b=4); // = function() 3<4;
|
||||
function f_lt(a,b) = f_2arg(function (a,b) a<b)(a,b);
|
||||
// fn_3lt4 = f_lt(3,4); // = function() 3<4;
|
||||
function f_lt(a,b) = f_2arg_simple(function (a,b) a<b)(a,b);
|
||||
|
||||
|
||||
// Function: f_gte()
|
||||
// Usage:
|
||||
// fn = f_gte();
|
||||
// fn = f_gte(a=);
|
||||
// fn = f_gte(b=);
|
||||
// fn = f_gte(a=,b=);
|
||||
// fn = f_gte(b);
|
||||
// fn = f_gte(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.
|
||||
// A factory that generates function literals based on `a >= b`, where one
|
||||
// or both of the arguments can be replaced with constants.
|
||||
// Example:
|
||||
// fn_gte = f_gte(); // = function(a,b) a>=b;
|
||||
// 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);
|
||||
// fn_3gte4 = f_gte(3,4); // = function() 3>=4;
|
||||
function f_gte(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// A factory that generates function literals based on `a <= b`, where
|
||||
// one or both arguments can be replaced with constants.
|
||||
// Example:
|
||||
// fn_lte = f_lte(); // = function(a,b) a<=b;
|
||||
// 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);
|
||||
// fn_3lte4 = f_lte(3,4); // = function() 3<=4;
|
||||
function f_lte(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// A factory that generates function literals based on `a == b`, where
|
||||
// one or both arguments can be replaced with constants.
|
||||
// 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);
|
||||
// fn_eq3 = f_eq(3); // = function(a) a==3;
|
||||
// fn_3eq4 = f_eq(3,4); // = function() 3==4;
|
||||
function f_eq(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// A factory that generates function literals based on `a != b`, where
|
||||
// one or both arguments can be replaced with constants.
|
||||
// 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);
|
||||
// fn_neq3 = f_neq(3); // = function(a) a!=3;
|
||||
// fn_3neq4 = f_neq(3,4); // = function() 3!=4;
|
||||
function f_neq(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// one or both arguments can be replaced with constants.
|
||||
// Example:
|
||||
// fn_approx = f_approx(); // = function(a,b) approx(a,b);
|
||||
// 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);
|
||||
// fn_3approx4 = f_approx(3,4); // = function() approx(3,4);
|
||||
function f_approx(a,b) = f_2arg_simple(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=);
|
||||
// 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.
|
||||
// A factory that generates function literals based on `!approx(a,b)`, where
|
||||
// one or both arguments can be replaced with constants.
|
||||
// Example:
|
||||
// fn_napprox = f_napprox(); // = function(a,b) napprox(a,b);
|
||||
// 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);
|
||||
// fn_3napprox4 = f_napprox(3,4); // = function() napprox(3,4);
|
||||
function f_napprox(a,b) = f_2arg_simple(function (a,b) !approx(a,b))(a,b);
|
||||
|
||||
|
||||
|
||||
|
|
182
geometry.scad
182
geometry.scad
|
@ -488,7 +488,7 @@ function _covariance_evec_eval(points) =
|
|||
evals = _eigenvals_symm_3(M), // eigenvalues in decreasing order
|
||||
evec = _eigenvec_symm_3(M,evals,i=2) )
|
||||
[pm, evec, evals[0] ];
|
||||
|
||||
|
||||
|
||||
// Function: plane_from_points()
|
||||
// Usage:
|
||||
|
@ -1638,17 +1638,26 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// Description:
|
||||
// Given a simple polygon in 2D or 3D, triangulates it and returns a list
|
||||
// of triples indexing into the polygon vertices. When the optional argument `ind` is
|
||||
// given, the it is used as an index list into `poly` to define the polygon. In that case,
|
||||
// `poly` may have a length greater than `ind`. Otherwise, all points in `poly`
|
||||
// given, it is used as an index list into `poly` to define the polygon. In that case,
|
||||
// `poly` may have a length greater than `ind`. When `ind` is undefined, all points in `poly`
|
||||
// are considered as vertices of the polygon.
|
||||
// .
|
||||
// The function may issue an error if it finds that the polygon is not simple
|
||||
// (self-intersecting) or its vertices are collinear. It can work for 3d non-planar polygons
|
||||
// if they are close enough to planar but may otherwise issue an error for this case.
|
||||
// .
|
||||
// For 2d polygons, the output triangles will have the same winding (CW or CCW) of
|
||||
// the input polygon. For 3d polygons, the triangle windings will induce a normal
|
||||
// vector with the same direction of the polygon normal.
|
||||
// .
|
||||
// The function produce correct triangulations for some non-twisted non-simple polygons.
|
||||
// A polygon is non-twisted iff it is simple or there is a partition of it in
|
||||
// simple polygons with the same winding. These polygons may have "touching" vertices
|
||||
// (two vertices having the same coordinates, but distinct adjacencies) and "contact" edges
|
||||
// (edges whose vertex pairs have the same pairwise coordinates but are in reversed order) but has
|
||||
// no self-crossing. See examples bellow. If all polygon edges are contact edges,
|
||||
// it returns an empty list for 2d polygons and issues an error for 3d polygons.
|
||||
// .
|
||||
// Self-crossing polygons have no consistent winding and usually produce an error but
|
||||
// when an error is not issued the outputs are not correct triangulations. The function
|
||||
// can work for 3d non-planar polygons if they are close enough to planar but may otherwise
|
||||
// issue an error for this case.
|
||||
// Arguments:
|
||||
// poly = Array of vertices for the polygon.
|
||||
// ind = A list indexing the vertices of the polygon in `poly`.
|
||||
|
@ -1656,7 +1665,32 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// Example(2D,NoAxes):
|
||||
// poly = star(id=10, od=15,n=11);
|
||||
// tris = polygon_triangulate(poly);
|
||||
// for(tri=tris) stroke(select(poly,tri), width=.2, closed=true);
|
||||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([poly,[]],faces=false,size=1);
|
||||
// Example(2D,NoAxes): a polygon with a hole and one "contact" edge
|
||||
// poly = [ [-10,0], [10,0], [0,10], [-10,0], [-4,4], [4,4], [0,2], [-4,4] ];
|
||||
// tris = polygon_triangulate(poly);
|
||||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([poly,[]],faces=false,size=1);
|
||||
// Example(2D,NoAxes): a polygon with "touching" vertices and no holes
|
||||
// poly = [ [0,0], [5,5], [-5,5], [0,0], [-5,-5], [5,-5] ];
|
||||
// tris = polygon_triangulate(poly);
|
||||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([poly,[]],faces=false,size=1);
|
||||
// Example(2D,NoAxes): a polygon with "contact" edges and no holes
|
||||
// poly = [ [0,0], [10,0], [10,10], [0,10], [0,0], [3,3], [7,3],
|
||||
// [7,7], [7,3], [3,3] ];
|
||||
// tris = polygon_triangulate(poly); // see from the top
|
||||
// color("lightblue") for(tri=tris) polygon(select(poly,tri));
|
||||
// color("blue") up(1) for(tri=tris) { stroke(select(poly,tri),.15,closed=true); }
|
||||
// color("magenta") up(2) stroke(poly,.25,closed=true);
|
||||
// color("black") up(3) vnf_debug([poly,[]],faces=false,size=1);
|
||||
// Example(3D):
|
||||
// include <BOSL2/polyhedra.scad>
|
||||
// vnf = regular_polyhedron_info(name="dodecahedron",side=5,info="vnf");
|
||||
|
@ -1665,82 +1699,42 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
|||
// color("blue")
|
||||
// vnf_wireframe(vnf_tri, width=.15);
|
||||
function polygon_triangulate(poly, ind, eps=EPSILON) =
|
||||
assert(is_path(poly), "Polygon `poly` should be a list of 2d or 3d points")
|
||||
assert(is_path(poly) && len(poly)>=3, "Polygon `poly` should be a list of at least three 2d or 3d points")
|
||||
assert(is_undef(ind)
|
||||
|| (is_vector(ind) && min(ind)>=0 && max(ind)<len(poly) ),
|
||||
"Improper or out of bounds list of indices")
|
||||
let( ind = deduplicate_indexed(poly,is_undef(ind) ? count(len(poly)) : ind) )
|
||||
len(ind) == 3 ? [ind] :
|
||||
len(ind) < 3 ? [] :
|
||||
len(poly[ind[0]]) == 3
|
||||
? // represents the polygon projection on its plane as a 2d polygon
|
||||
let(
|
||||
pts = select(poly,ind),
|
||||
nrm = polygon_normal(pts)
|
||||
)
|
||||
// here, instead of an error, it might return [] or undef
|
||||
assert( nrm!=undef,
|
||||
"The polygon has self-intersections or its vertices are collinear or non coplanar.")
|
||||
let(
|
||||
imax = max_index([for(p=pts) norm(p-pts[0]) ]),
|
||||
v1 = unit( pts[imax] - pts[0] ),
|
||||
v2 = cross(v1,nrm),
|
||||
prpts = pts*transpose([v1,v2])
|
||||
)
|
||||
[for(tri=_triangulate(prpts, count(len(ind)), eps)) select(ind,tri) ]
|
||||
: let( cw = is_polygon_clockwise(select(poly, ind)) )
|
||||
cw
|
||||
? [for(tri=_triangulate( poly, reverse(ind), eps )) reverse(tri) ]
|
||||
: _triangulate( poly, ind, eps );
|
||||
let( ind = is_undef(ind) ? count(len(poly)) : ind )
|
||||
len(ind) == 3
|
||||
? _is_degenerate([poly[ind[0]], poly[ind[1]], poly[ind[2]]], eps) ? [] :
|
||||
// non zero area
|
||||
assert( norm(scalar_vec3(cross(poly[ind[1]]-poly[ind[0]], poly[ind[2]]-poly[ind[0]]))) > 2*eps,
|
||||
"The polygon vertices are collinear.")
|
||||
[ind]
|
||||
: len(poly[ind[0]]) == 3
|
||||
? // represents the polygon projection on its plane as a 2d polygon
|
||||
let(
|
||||
ind = deduplicate_indexed(poly, ind, eps)
|
||||
)
|
||||
len(ind)<3 ? [] :
|
||||
let(
|
||||
pts = select(poly,ind),
|
||||
nrm = polygon_normal(pts)
|
||||
)
|
||||
assert( nrm!=undef,
|
||||
"The polygon has self-intersections or its vertices are collinear or non coplanar.")
|
||||
let(
|
||||
imax = max_index([for(p=pts) norm(p-pts[0]) ]),
|
||||
v1 = unit( pts[imax] - pts[0] ),
|
||||
v2 = cross(v1,nrm),
|
||||
prpts = pts*transpose([v1,v2])
|
||||
)
|
||||
[for(tri=_triangulate(prpts, count(len(ind)), eps)) select(ind,tri) ]
|
||||
: let( cw = is_polygon_clockwise(select(poly, ind)) )
|
||||
cw
|
||||
? [for(tri=_triangulate( poly, reverse(ind), eps )) reverse(tri) ]
|
||||
: _triangulate( poly, ind, eps );
|
||||
|
||||
|
||||
|
||||
// requires ccw 2d polygons
|
||||
// returns ccw triangles
|
||||
function _old_triangulate(poly, ind, eps=EPSILON, tris=[]) =
|
||||
len(ind)==3 ? concat(tris,[ind]) :
|
||||
let( ear = _get_ear(poly,ind,eps) )
|
||||
assert( ear!=undef,
|
||||
"The polygon has self-intersections or its vertices are collinear or non coplanar.")
|
||||
let(
|
||||
ear_tri = select(ind,ear,ear+2),
|
||||
indr = select(ind,ear+2, ear) // indices of the remaining points
|
||||
)
|
||||
_triangulate(poly, indr, eps, concat(tris,[ear_tri]));
|
||||
|
||||
// search a valid ear from the remaining polygon
|
||||
function _old_get_ear(poly, ind, eps, _i=0) =
|
||||
_i>=len(ind) ? undef : // poly has no ears
|
||||
let( // the _i-th ear candidate
|
||||
p0 = poly[ind[_i]],
|
||||
p1 = poly[ind[(_i+1)%len(ind)]],
|
||||
p2 = poly[ind[(_i+2)%len(ind)]]
|
||||
)
|
||||
// if it is not a convex vertex, try the next one
|
||||
_is_cw2(p0,p1,p2,eps) ? _get_ear(poly,ind,eps, _i=_i+1) :
|
||||
let( // vertex p1 is convex; check if the triangle contains any other point
|
||||
to_tst = select(ind,_i+3, _i-1),
|
||||
pt2tst = select(poly,to_tst), // points other than p0, p1 and p2
|
||||
q = [(p0-p2).y, (p2-p0).x], // orthogonal to ray [p0,p2] pointing right
|
||||
q0 = q*p0,
|
||||
atleft = [for(p=pt2tst) if(p*q<=q0) p ]
|
||||
)
|
||||
atleft==[] ? _i : // no point inside -> an ear
|
||||
let(
|
||||
q = [(p2-p1).y, (p1-p2).x], // orthogonal to ray [p1,p2] pointing right
|
||||
q0 = q*p2,
|
||||
atleft = [for(p=atleft) if(p*q<=q0) p ]
|
||||
)
|
||||
atleft==[] ? _i : // no point inside -> an ear
|
||||
let(
|
||||
q = [(p1-p0).y, (p0-p1).x], // orthogonal to ray [p1,p0] pointing right
|
||||
q0 = q*p1,
|
||||
atleft = [for(p=atleft) if(p*q<=q0) p ]
|
||||
)
|
||||
atleft==[] ? _i : // no point inside -> an ear
|
||||
// check the next ear candidate
|
||||
_get_ear(poly, ind, eps, _i=_i+1);
|
||||
|
||||
function _triangulate(poly, ind, eps=EPSILON, tris=[]) =
|
||||
len(ind)==3
|
||||
? _is_degenerate(select(poly,ind),eps)
|
||||
|
@ -1749,18 +1743,18 @@ function _triangulate(poly, ind, eps=EPSILON, tris=[]) =
|
|||
: let( ear = _get_ear(poly,ind,eps) )
|
||||
assert( ear!=undef,
|
||||
"The polygon has self-intersections or its vertices are collinear or non coplanar.")
|
||||
ear<0 // degenerate ear
|
||||
? let( indr = select(ind,-ear+1, -ear-1) ) // discard it
|
||||
_triangulate(poly, indr, eps, tris)
|
||||
is_list(ear) // degenerate ear
|
||||
? _triangulate(poly, select(ind,ear[0]+2, ear[0]), eps, tris) // discard it
|
||||
: let(
|
||||
ear_tri = select(ind,ear,ear+2),
|
||||
indr = select(ind,ear+2, ear) // indices of the remaining points
|
||||
indr = select(ind,ear+2, ear) // remaining point indices
|
||||
)
|
||||
_triangulate(poly, indr, eps, concat(tris,[ear_tri]));
|
||||
|
||||
|
||||
// a returned ear will be:
|
||||
// 1. a CCW triangle without points inside except possibly at its vertices
|
||||
// 1. a CCW (non-degenerate) triangle, made of subsequent vertices, without other
|
||||
// points inside except possibly at its vertices
|
||||
// 2. or a degenerate triangle where two vertices are coincident
|
||||
// the returned ear is specified by the index of `ind` of its first vertex
|
||||
function _get_ear(poly, ind, eps, _i=0) =
|
||||
|
@ -1770,29 +1764,25 @@ function _get_ear(poly, ind, eps, _i=0) =
|
|||
p1 = poly[ind[(_i+1)%len(ind)]],
|
||||
p2 = poly[ind[(_i+2)%len(ind)]]
|
||||
)
|
||||
// if it is a degenerate triangle, return it (codified)
|
||||
_is_degenerate([p0,p1,p2],eps) ? -(_i+1) :
|
||||
// if it is not a convex vertex, try the next one
|
||||
// degenerate triangles are returned codified
|
||||
_is_degenerate([p0,p1,p2],eps) ? [_i] :
|
||||
// if it is not a convex vertex, check the next one
|
||||
_is_cw2(p0,p1,p2,eps) ? _get_ear(poly,ind,eps, _i=_i+1) :
|
||||
let( // vertex p1 is convex
|
||||
// check if the triangle contains any other point
|
||||
// except possibly its own vertices
|
||||
to_tst = select(ind,_i+3, _i-1),
|
||||
pt2tst = select(poly,to_tst), // points other than p0, p1 and p2
|
||||
q = [(p0-p2).y, (p2-p0).x], // orthogonal to ray [p0,p2] pointing right
|
||||
q0 = q*p0,
|
||||
r = [(p2-p1).y, (p1-p2).x], // orthogonal to ray [p2,p1] pointing right
|
||||
r0 = r*p2,
|
||||
s = [(p1-p0).y, (p0-p1).x], // orthogonal to ray [p1,p0] pointing right
|
||||
s0 = s*p1,
|
||||
inside = [for(p=pt2tst)
|
||||
if( p*q<=q0 && p*r<=r0 && p*s<=s0 ) // p is in the triangle
|
||||
if( norm(p-p0)>eps // and doesn't coincide with
|
||||
&& norm(p-p1)>eps // any of its vertices
|
||||
inside = [for(p=select(poly,to_tst)) // for vertices other than p0, p1 and p2
|
||||
if( (p-p0)*q<=0 && (p-p2)*r<=0 && (p-p1)*s<=0 // p is on the triangle
|
||||
&& norm(p-p0)>eps // but not on any vertex of it
|
||||
&& norm(p-p1)>eps
|
||||
&& norm(p-p2)>eps )
|
||||
p ]
|
||||
)
|
||||
inside==[] ? _i : // no point inside -> an ear
|
||||
inside==[] ? _i : // found an ear
|
||||
// check the next ear candidate
|
||||
_get_ear(poly, ind, eps, _i=_i+1);
|
||||
|
||||
|
|
13
math.scad
13
math.scad
|
@ -689,17 +689,12 @@ function _sum(v,_total,_i=0) = _i>=len(v) ? _total : _sum(v,_total+v[_i], _i+1);
|
|||
// cumsum([[1,2,3], [3,4,5], [5,6,7]]); // returns [[1,2,3], [4,6,8], [9,12,15]]
|
||||
function cumsum(v) =
|
||||
assert(is_consistent(v), "The input is not consistent." )
|
||||
_cumsum(v,_i=0,_acc=[]);
|
||||
len(v)<=1 ? v :
|
||||
_cumsum(v,_i=1,_acc=[v[0]]);
|
||||
|
||||
function _cumsum(v,_i=0,_acc=[]) =
|
||||
_i==len(v) ? _acc :
|
||||
_cumsum(
|
||||
v, _i+1,
|
||||
concat(
|
||||
_acc,
|
||||
[_i==0 ? v[_i] : last(_acc) + v[_i]]
|
||||
)
|
||||
);
|
||||
_i>=len(v) ? _acc :
|
||||
_cumsum( v, _i+1, [ each _acc, _acc[len(_acc)-1] + v[_i] ] );
|
||||
|
||||
|
||||
// Function: sum_of_sines()
|
||||
|
|
|
@ -83,23 +83,23 @@ test_for_n();
|
|||
|
||||
|
||||
module test_find_first() {
|
||||
l = [7,3,9,1,6,1,3,2];
|
||||
l = [7,3,8,1,6,1,3,2,9];
|
||||
lt = function (val,x) val < x;
|
||||
lte = function (val,x) val <= x;
|
||||
gt = function (val,x) val > x;
|
||||
gte = function (val,x) val >= x;
|
||||
assert_equal(find_first(1,l), 3);
|
||||
assert_equal(find_first(1,l,start=4), 5);
|
||||
assert_equal(find_first(6,l), 4);
|
||||
assert_equal(find_first(3,l,func=gt ), 3);
|
||||
assert_equal(find_first(3,l,func=gte), 1);
|
||||
assert_equal(find_first(3,l,func=lt ), 0);
|
||||
assert_equal(find_first(7,l,func=lt ), 2);
|
||||
assert_equal(find_first(7,l,func=lte), 0);
|
||||
assert_equal(find_first(7,l,start=1,func=gte), 1);
|
||||
assert_equal(find_first(7,l,start=3,func=gte), 3);
|
||||
assert_equal(find_first(f_eq(1),l), 3);
|
||||
assert_equal(find_first(f_eq(1),l,start=4), 5);
|
||||
assert_equal(find_first(f_eq(6),l), 4);
|
||||
assert_equal(find_first(f_gt(8),l), 8);
|
||||
assert_equal(find_first(f_gte(8),l), 2);
|
||||
assert_equal(find_first(f_lt(3),l), 3);
|
||||
assert_equal(find_first(f_lt(7),l), 1);
|
||||
assert_equal(find_first(f_lte(8),l), 0);
|
||||
assert_equal(find_first(f_gte(8),l,start=1), 2);
|
||||
assert_equal(find_first(f_gte(8),l,start=3), 8);
|
||||
}
|
||||
//test_find_first();
|
||||
test_find_first();
|
||||
|
||||
|
||||
module test_binsearch() {
|
||||
|
@ -127,8 +127,8 @@ test_simple_hash();
|
|||
|
||||
|
||||
module test_f_1arg() {
|
||||
assert_equal(str(f_1arg(function (x) x)), "function(a) ((a == undef) ? function(x) func(x) : function() func(a))");
|
||||
assert_equal(str(f_1arg(function (x) x)(3)), "function() func(a)");
|
||||
assert_equal(str(f_1arg(function (x) x)), "function(a) ((a == undef) ? function(x) target_func(x) : function() target_func(a))");
|
||||
assert_equal(str(f_1arg(function (x) x)(3)), "function() target_func(a)");
|
||||
assert_equal(f_1arg(function (x) x)()(4), 4);
|
||||
assert_equal(f_1arg(function (x) x)(3)(), 3);
|
||||
}
|
||||
|
@ -136,11 +136,11 @@ test_f_1arg();
|
|||
|
||||
|
||||
module test_f_2arg() {
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)), "function(a, b) (((a == undef) && (b == undef)) ? function(x, y) func(x, y) : ((a == undef) ? function(x) func(x, b) : ((b == undef) ? function(x) func(a, x) : function() func(a, b))))");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(3)), "function(x) func(a, x)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(a=3)), "function(x) func(a, x)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(b=3)), "function(x) func(x, b)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(3,4)), "function() func(a, b)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)), "function(a, b) (((a == undef) && (b == undef)) ? function(x, y) target_func(x, y) : ((a == undef) ? function(x) target_func(x, b) : ((b == undef) ? function(x) target_func(a, x) : function() target_func(a, b))))");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(3)), "function(x) target_func(a, x)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(a=3)), "function(x) target_func(a, x)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(b=3)), "function(x) target_func(x, b)");
|
||||
assert_equal(str(f_2arg(function (a,b) a+b)(3,4)), "function() target_func(a, b)");
|
||||
assert_equal(f_2arg(function (a,b) a+b)()(4,2), 6);
|
||||
assert_equal(f_2arg(function (a,b) a+b)(3)(7), 10);
|
||||
assert_equal(f_2arg(function (a,b) a+b)(a=2)(7), 9);
|
||||
|
@ -150,10 +150,10 @@ test_f_2arg();
|
|||
|
||||
|
||||
module test_f_3arg() {
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)), "function(a, b, c) ((((a == undef) && (b == undef)) && (c == undef)) ? function(x, y, z) func(x, y, z) : (((a == undef) && (b == undef)) ? function(x, y) func(x, y, c) : (((a == undef) && (c == undef)) ? function(x, y) func(x, b, y) : (((b == undef) && (c == undef)) ? function(x, y) func(a, x, y) : ((a == undef) ? function(x) func(x, b, c) : ((b == undef) ? function(x) func(a, x, c) : ((c == undef) ? function(x) func(a, b, x) : function() func(a, b, c))))))))");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)(3)), "function(x, y) func(a, x, y)");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)(3,4)), "function(x) func(a, b, x)");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)(3,4,1)), "function() func(a, b, c)");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)), "function(a, b, c) ((((a == undef) && (b == undef)) && (c == undef)) ? function(x, y, z) target_func(x, y, z) : (((a == undef) && (b == undef)) ? function(x, y) target_func(x, y, c) : (((a == undef) && (c == undef)) ? function(x, y) target_func(x, b, y) : (((b == undef) && (c == undef)) ? function(x, y) target_func(a, x, y) : ((a == undef) ? function(x) target_func(x, b, c) : ((b == undef) ? function(x) target_func(a, x, c) : ((c == undef) ? function(x) target_func(a, b, x) : function() target_func(a, b, c))))))))");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)(3)), "function(x, y) target_func(a, x, y)");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)(3,4)), "function(x) target_func(a, b, x)");
|
||||
assert_equal(str(f_3arg(function (a,b,c) a+b+c)(3,4,1)), "function() target_func(a, b, c)");
|
||||
assert_equal(f_3arg(function (a,b,c) a+b+c)()(4,2,1), 7);
|
||||
assert_equal(f_3arg(function (a,b,c) a+b+c)(3)(7,3), 13);
|
||||
assert_equal(f_3arg(function (a,b,c) a+b+c)(a=2)(7,1), 10);
|
||||
|
@ -165,22 +165,22 @@ test_f_3arg();
|
|||
|
||||
|
||||
module test_ival() {
|
||||
assert_equal(str(ival(function (a) a)), "function(a, b) func(a)");
|
||||
assert_equal(str(ival(function (a) a)), "function(a, b) target_func(a)");
|
||||
assert_equal(ival(function (a) a)(3,5), 3);
|
||||
}
|
||||
test_ival();
|
||||
|
||||
|
||||
module test_xval() {
|
||||
assert_equal(str(xval(function (a) a)), "function(a, b) func(b)");
|
||||
assert_equal(str(xval(function (a) a)), "function(a, b) target_func(b)");
|
||||
assert_equal(xval(function (a) a)(3,5), 5);
|
||||
}
|
||||
test_xval();
|
||||
|
||||
|
||||
module _test_fn1arg(dafunc,tests) {
|
||||
assert_equal(str(dafunc()), "function(x) func(x)");
|
||||
assert_equal(str(dafunc(3)), "function() func(a)");
|
||||
assert_equal(str(dafunc()), "function(x) target_func(x)");
|
||||
assert_equal(str(dafunc(3)), "function() target_func(a)");
|
||||
for (test = tests) {
|
||||
a = test[0];
|
||||
r = test[1];
|
||||
|
@ -191,11 +191,11 @@ module _test_fn1arg(dafunc,tests) {
|
|||
|
||||
|
||||
module _test_fn2arg(dafunc,tests) {
|
||||
assert_equal(str(dafunc()), "function(x, y) func(x, y)");
|
||||
assert_equal(str(dafunc(3)), "function(x) func(a, x)");
|
||||
assert_equal(str(dafunc(a=3)), "function(x) func(a, x)");
|
||||
assert_equal(str(dafunc(b=3)), "function(x) func(x, b)");
|
||||
assert_equal(str(dafunc(3,4)), "function() func(a, b)");
|
||||
assert_equal(str(dafunc()), "function(x, y) target_func(x, y)");
|
||||
assert_equal(str(dafunc(3)), "function(x) target_func(a, x)");
|
||||
assert_equal(str(dafunc(a=3)), "function(x) target_func(a, x)");
|
||||
assert_equal(str(dafunc(b=3)), "function(x) target_func(x, b)");
|
||||
assert_equal(str(dafunc(3,4)), "function() target_func(a, b)");
|
||||
for (test = tests) {
|
||||
a = test[0];
|
||||
b = test[1];
|
||||
|
@ -210,17 +210,33 @@ module _test_fn2arg(dafunc,tests) {
|
|||
}
|
||||
|
||||
|
||||
module _test_fn2arg_simple(dafunc,tests) {
|
||||
assert_equal(str(dafunc()), "function(x, y) target_func(x, y)");
|
||||
assert_equal(str(dafunc(3)), "function(x) target_func(x, a)");
|
||||
assert_equal(str(dafunc(3,4)), "function() target_func(a, b)");
|
||||
for (test = tests) {
|
||||
a = test[0];
|
||||
b = test[1];
|
||||
r = test[2];
|
||||
assert_equal(dafunc(a=a,b=b)(), r);
|
||||
assert_equal(dafunc(a,b)(), r);
|
||||
assert_equal(dafunc(b)(a), r);
|
||||
assert_equal(dafunc()(a,b), r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module _test_fn3arg(dafunc,tests) {
|
||||
assert_equal(str(dafunc()), "function(x, y, z) func(x, y, z)");
|
||||
assert_equal(str(dafunc(3)), "function(x, y) func(a, x, y)");
|
||||
assert_equal(str(dafunc(a=3)), "function(x, y) func(a, x, y)");
|
||||
assert_equal(str(dafunc(b=3)), "function(x, y) func(x, b, y)");
|
||||
assert_equal(str(dafunc(c=3)), "function(x, y) func(x, y, c)");
|
||||
assert_equal(str(dafunc(3,4)), "function(x) func(a, b, x)");
|
||||
assert_equal(str(dafunc(a=3,b=4)), "function(x) func(a, b, x)");
|
||||
assert_equal(str(dafunc(a=3,c=4)), "function(x) func(a, x, c)");
|
||||
assert_equal(str(dafunc(b=3,c=4)), "function(x) func(x, b, c)");
|
||||
assert_equal(str(dafunc(3,4,5)), "function() func(a, b, c)");
|
||||
assert_equal(str(dafunc()), "function(x, y, z) target_func(x, y, z)");
|
||||
assert_equal(str(dafunc(3)), "function(x, y) target_func(a, x, y)");
|
||||
assert_equal(str(dafunc(a=3)), "function(x, y) target_func(a, x, y)");
|
||||
assert_equal(str(dafunc(b=3)), "function(x, y) target_func(x, b, y)");
|
||||
assert_equal(str(dafunc(c=3)), "function(x, y) target_func(x, y, c)");
|
||||
assert_equal(str(dafunc(3,4)), "function(x) target_func(a, b, x)");
|
||||
assert_equal(str(dafunc(a=3,b=4)), "function(x) target_func(a, b, x)");
|
||||
assert_equal(str(dafunc(a=3,c=4)), "function(x) target_func(a, x, c)");
|
||||
assert_equal(str(dafunc(b=3,c=4)), "function(x) target_func(x, b, c)");
|
||||
assert_equal(str(dafunc(3,4,5)), "function() target_func(a, b, c)");
|
||||
for (test = tests) {
|
||||
a = test[0];
|
||||
b = test[1];
|
||||
|
@ -241,7 +257,7 @@ module _test_fn3arg(dafunc,tests) {
|
|||
|
||||
|
||||
module test_f_cmp() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_cmp(a,b),
|
||||
[[4,3,1],[3,3,0],[3,4,-1]]
|
||||
);
|
||||
|
@ -250,7 +266,7 @@ test_f_cmp();
|
|||
|
||||
|
||||
module test_f_gt() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_gt(a,b),
|
||||
[[4,3,true],[3,3,false],[3,4,false]]
|
||||
);
|
||||
|
@ -259,7 +275,7 @@ test_f_gt();
|
|||
|
||||
|
||||
module test_f_gte() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_gte(a,b),
|
||||
[[4,3,true],[3,3,true],[3,4,false]]
|
||||
);
|
||||
|
@ -268,7 +284,7 @@ test_f_gte();
|
|||
|
||||
|
||||
module test_f_lt() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_lt(a,b),
|
||||
[[4,3,false],[3,3,false],[3,4,true]]
|
||||
);
|
||||
|
@ -277,7 +293,7 @@ test_f_lt();
|
|||
|
||||
|
||||
module test_f_lte() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_lte(a,b),
|
||||
[[4,3,false],[3,3,true],[3,4,true]]
|
||||
);
|
||||
|
@ -286,7 +302,7 @@ test_f_lte();
|
|||
|
||||
|
||||
module test_f_eq() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_eq(a,b),
|
||||
[[4,3,false],[3,3,true],[3,4,false]]
|
||||
);
|
||||
|
@ -295,7 +311,7 @@ test_f_eq();
|
|||
|
||||
|
||||
module test_f_neq() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_neq(a,b),
|
||||
[[4,3,true],[3,3,false],[3,4,true]]
|
||||
);
|
||||
|
@ -304,7 +320,7 @@ test_f_neq();
|
|||
|
||||
|
||||
module test_f_approx() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_approx(a,b),
|
||||
[[4,3,false],[3,3,true],[3,4,false],[1/3,0.33333333333333333333333333,true]]
|
||||
);
|
||||
|
@ -313,7 +329,7 @@ test_f_approx();
|
|||
|
||||
|
||||
module test_f_napprox() {
|
||||
_test_fn2arg(
|
||||
_test_fn2arg_simple(
|
||||
function (a,b) f_napprox(a,b),
|
||||
[[4,3,true],[3,3,false],[3,4,true],[1/3,0.33333333333333333333333333,false]]
|
||||
);
|
||||
|
|
|
@ -48,6 +48,7 @@ test_reindex_polygon();
|
|||
test_align_polygon();
|
||||
test_centroid();
|
||||
test_point_in_polygon();
|
||||
test_polygon_triangulate();
|
||||
test_is_polygon_clockwise();
|
||||
test_clockwise_polygon();
|
||||
test_ccw_polygon();
|
||||
|
@ -78,6 +79,21 @@ function info_str(list,i=0,string=chr(10)) =
|
|||
: info_str(list,i+1,str(string,str(list[i][0],_valstr(list[i][1]),chr(10))));
|
||||
|
||||
|
||||
module test_polygon_triangulate() {
|
||||
poly0 = [ [0,0,1], [10,0,2], [10,10,0] ];
|
||||
poly1 = [ [-10,0,-10], [10,0,10], [0,10,0], [-10,0,-10], [-4,4,-4], [4,4,4], [0,2,0], [-4,4,-4] ];
|
||||
poly2 = [ [0,0], [5,5], [-5,5], [0,0], [-5,-5], [5,-5] ];
|
||||
poly3 = [ [0,0], [10,0], [10,10], [10,13], [10,10], [0,10], [0,0], [3,3], [7,3], [7,7], [7,3], [3,3] ];
|
||||
tris0 = sort(polygon_triangulate(poly0));
|
||||
assert(approx(tris0, [[0, 1, 2]]));
|
||||
tris1 = (polygon_triangulate(poly1));
|
||||
assert(approx(tris1,( [[2, 3, 4], [6, 7, 0], [2, 4, 5], [6, 0, 1], [1, 2, 5], [5, 6, 1]])));
|
||||
tris2 = (polygon_triangulate(poly2));
|
||||
assert(approx(tris2,([[0, 1, 2], [3, 4, 5]])));
|
||||
tris3 = (polygon_triangulate(poly3));
|
||||
assert(approx(tris3,( [[5, 6, 7], [7, 8, 9], [10, 11, 0], [5, 7, 9], [10, 0, 1], [4, 5, 9], [9, 10, 1], [1, 4, 9]])));
|
||||
}
|
||||
|
||||
module test__normalize_plane(){
|
||||
plane = rands(-5,5,4,seed=333)+[10,0,0,0];
|
||||
plane2 = _normalize_plane(plane);
|
||||
|
|
Loading…
Reference in a new issue