Added more flexibility to get_named_args(), and all the left_half(), etc. as functions

This commit is contained in:
Jerome Plut 2020-12-03 21:21:05 +01:00
parent be8b1036d8
commit 1d324128e4
4 changed files with 112 additions and 40 deletions

View file

@ -89,6 +89,18 @@ function select(list, start, end=undef) =
: concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]]) ;
// Function: last()
// Description:
// Returns the last element of a list, or undef if empty.
// Usage:
// last(list)
// Arguments:
// list = The list to get the last element of.
// Example:
// l = [3,4,5,6,7,8,9];
// last(l); // Returns 9.
function last(list) = list[len(list)-1];
// Function: slice()
// Description:
// Returns a slice of a list. The first item is index 0.

View file

@ -312,27 +312,41 @@ function get_height(h=undef,l=undef,height=undef,dflt=undef) =
assert(num_defined([h,l,height])<=1,"You must specify only one of `l`, `h`, and `height`")
first_defined([h,l,height,dflt]);
// Function: get_named_args(anonymous, named, _undef)
// Function: get_named_args(positional, named, _undef)
// Usage:
// function f(anon1=_undef, anon2=_undef,...,
// function f(pos1=_undef, pos2=_undef,...,
// named1=_undef, named2=_undef, ...) =
// let(args = get_named_args([anon1, anon2, ...],
// [[named1, default1], [named2, default2], ...]))
// let(args = get_named_args([pos1, pos2, ...],
// [[named1, default1], [named2, default2], ...]),
// named1=args[0], named2=args[1], ...)
// ...
// Description:
// given a set of anonymous and named arguments, returns the values of
// named arguments, in order.
// - All named arguments which were provided by the user take the
// value provided.
// Given the values of some positional and named arguments,
// returns a list of the values assigned to named arguments,
// in the following way:
// - All named arguments which were explicitly assigned in the
// function call take the value provided.
// - All named arguments which were not provided by the user are
// affected from anonymous arguments, in order.
// affected from positional arguments; the priority order in which
// these are assigned is given by the `priority` argument, while the
// positional assignation is done in the order of the named arguments.
// - Any remaining named arguments take the provided default values.
// Arguments:
// anonymous = the list of values of anonymous arguments.
// named = the list of [passed-value, default value] of named arguments.
// _undef = the default value used by the calling function for all
// arguments (this is *not* undef, or any value that the user might
// purposely want to use as an argument value).
// positional = the list of values of positional arguments.
// named = the list of named arguments; each entry of the list has the
// form [passed-value, default-value, priority], where
// passed-value is the value that was passed at function call;
// default-value is the value that will be used if nothing is read
// from either named or positional arguments;
// priority is the priority assigned to this argument.
// _undef = the default value used by the calling function for all arguments (default is some random string that you will never use). (this is *not* undef, or any value that the user might purposely want to use as an argument value).
//
// If only k positional arguments are used, then the k named values
// with lowest 'priority' value (among the unassigned ones) will get them.
// The arguments will be assigned in the order of the named values.
// By default these two orders coincide.
//
//
// Examples:
// function f(arg1=_undef, arg2=_undef, arg3=_undef,
// named1=_undef, named2=_undef, named3=_undef) =
@ -349,16 +363,29 @@ function get_height(h=undef,l=undef,height=undef,dflt=undef) =
// result of `dd if=/dev/random bs=32 count=1 |base64` :
_undef="LRG+HX7dy89RyHvDlAKvb9Y04OTuaikpx205CTh8BSI";
function get_named_args(anonymous, named,_undef=_undef) =
/* u: set of undefined indices in named arguments */
let(from_anon = [for(p=enumerate(named)) if(p[1][0]==_undef) p[0]],
n = len(anonymous))
echo("from_anon:", from_anon)
/* Note: however tempting it might be, it is *not* possible to accept
* named argument as a list [named1, named2, ...] (without default
* values), because the values [named1, named2...] themselves might be
* lists, and we will not be able to distinguish the two cases. */
function get_named_args(positional, named,_undef=_undef) =
let(deft = [for(p=named) p[1]], // default is undef
// indices of the values to fetch from positional args:
unknown = [for(x=enumerate(named)) if(x[1][0]==_undef) x[0]],
// number of values given to positional arguments:
n_positional = count_true([for(p=positional) p!=_undef]))
assert(n_positional <= len(unknown),
str("too many positional arguments (", n_positional, " given, ",
len(unknown), " required)"))
let(
// those elements which have no priority assigned go last (prio=+):
prio = sortidx([for(u=unknown) default(named[u][2], 1/0)]),
// list of indices of values assigned from positional arguments:
assigned = sort([for(i=[0:1:n_positional-1]) prio[i]]))
[ for(e = enumerate(named))
// if the value is defined, return it:
e[1][0] != _undef ? e[1][0] :
let(k = anonymous[search(e[0], from_anon)[0]])
k != _undef ? k : e[1][1] ];
let(idx=e[0], val=e[1][0], ass=search(idx, assigned))
val != _undef ? val :
ass != [] ? positional[ass[0]] :
deft[idx] ];
// Function: scalar_vec3()
// Usage:
// scalar_vec3(v, <dflt>);

View file

@ -121,16 +121,9 @@ module half_of(v=UP, cp, s=1000, planar=false)
function half_of(_arg1=_undef, _arg2=_undef, _arg3=_undef, _arg4=_undef,
v=_undef, cp=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3, _arg4],
[[v], [cp, 0], [p], [s, 1e4]]),
[[v,undef,0], [cp,0,2], [p,undef,1], [s,1e4,3]]),
v=args[0], cp0=args[1], p=args[2], s=args[3],
cp = is_num(cp0) ? cp0*unit(v) : cp0)
echo("_undef=", _undef)
echo("v=", v)
echo("cp=", cp)
echo("p=", p)
echo("vnf?", is_vnf(p))
echo("region?", is_region(p))
echo("s=", s)
assert(is_vector(v,2)||is_vector(v,3),
"must provide a half-plane or half-space")
let(d=len(v))
@ -164,11 +157,15 @@ function half_of(_arg1=_undef, _arg2=_undef, _arg3=_undef, _arg4=_undef,
:
assert(false, "must pass either a point, a path, a region, or a VNF");
// Module: left_half()
// Function&Module: left_half()
//
// Usage:
// Usage: as module
// left_half([s], [x]) ...
// left_half(planar=true, [s], [x]) ...
// Usage: as function
// left_half([s], [x], path)
// left_half([s], [x], region)
// left_half([s], [x], vnf)
//
// Description:
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is right of it.
@ -197,10 +194,16 @@ module left_half(s=1000, x=0, planar=false)
}
}
}
function left_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
x=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3],
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
x=args[0], p=args[1], s=args[2])
half_of(v=[1,0,0], cp=x, p=p);
// Module: right_half()
// Function&Module: right_half()
//
// Usage:
// right_half([s], [x]) ...
@ -233,10 +236,16 @@ module right_half(s=1000, x=0, planar=false)
}
}
}
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
x=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3],
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
x=args[0], p=args[1], s=args[2])
half_of(v=[-1,0,0], cp=x, p=p);
// Module: front_half()
// Function&Module: front_half()
//
// Usage:
// front_half([s], [y]) ...
@ -269,10 +278,16 @@ module front_half(s=1000, y=0, planar=false)
}
}
}
function front_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
x=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3],
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
x=args[0], p=args[1], s=args[2])
half_of(v=[0,1,0], cp=x, p=p);
// Module: back_half()
// Function&Module: back_half()
//
// Usage:
// back_half([s], [y]) ...
@ -305,10 +320,16 @@ module back_half(s=1000, y=0, planar=false)
}
}
}
function back_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
x=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3],
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
x=args[0], p=args[1], s=args[2])
half_of(v=[0,-1,0], cp=x, p=p);
// Module: bottom_half()
// Function&Module: bottom_half()
//
// Usage:
// bottom_half([s], [z]) ...
@ -333,10 +354,16 @@ module bottom_half(s=1000, z=0)
}
}
}
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
x=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3],
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
x=args[0], p=args[1], s=args[2])
half_of(v=[0,0,-1], cp=x, p=p);
// Module: top_half()
// Function&Module: top_half()
//
// Usage:
// top_half([s], [z]) ...
@ -361,6 +388,12 @@ module top_half(s=1000, z=0)
}
}
}
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
x=_undef, p=_undef, s=_undef) =
let(args=get_named_args([_arg1, _arg2, _arg3],
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
x=args[0], p=args[1], s=args[2])
half_of(v=[0,0,1], cp=x, p=p);

View file

@ -924,7 +924,7 @@ function _vnf_halfspace_paths(edges, i=0, paths=[]) =
*/
i >= len(edges) ? paths : // termination condition
let(e = edges[i],
s = [for(x=enumerate(paths)) if(x[1][len(x[1])-1] == e[0]) x[0]])
s = [for(x=enumerate(paths)) if(last(x[1]) == e[0]) x[0]])
_vnf_halfspace_paths(edges, i+1,
// if cannot attach to previous path: create a new one
s == [] ? concat(paths, [e]) :
@ -947,7 +947,7 @@ function vnf_halfspace(_arg1=_undef, _arg2=_undef,
newedges=[for(x=tmp2) each x[1]],
// generate new faces
paths=_vnf_halfspace_paths(newedges),
loops=[for(p=paths) if(p[0] == p[len(p)-1]) p])
loops=[for(p=paths) if(p[0] == last(p)) p])
[coords, concat(newfaces, loops)];
//