mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-02-19 10:09:39 +00:00
Wrote better documentation for get_named_args()
This commit is contained in:
parent
abc8881b00
commit
8b22f3da08
3 changed files with 79 additions and 51 deletions
82
common.scad
82
common.scad
|
@ -312,38 +312,67 @@ 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`")
|
assert(num_defined([h,l,height])<=1,"You must specify only one of `l`, `h`, and `height`")
|
||||||
first_defined([h,l,height,dflt]);
|
first_defined([h,l,height,dflt]);
|
||||||
|
|
||||||
// Function: get_named_args(positional, named, _undef)
|
// Function: get_named_args()
|
||||||
// Usage:
|
// Usage:
|
||||||
// function f(pos1=_undef, pos2=_undef,...,named1=_undef, named2=_undef, ...) = let(args = get_named_args([pos1, pos2, ...], [[named1, default1], [named2, default2], ...]), named1=args[0], named2=args[1], ...)
|
// function f(pos1=_undef, pos2=_undef,...,named1=_undef, named2=_undef, ...) = let(args = get_named_args([pos1, pos2, ...], [[named1, default1], [named2, default2], ...]), named1=args[0], named2=args[1], ...)
|
||||||
// Description:
|
// Description:
|
||||||
// Given the values of some positional and named arguments,
|
// Given the values of some positional and named arguments,
|
||||||
// returns a list of the values assigned to named arguments,
|
// returns a list of the values assigned to named parameters.
|
||||||
// in the following way:
|
// in the following steps:
|
||||||
// - All named arguments which were explicitly assigned in the
|
// - First, all named parameters which were explicitly assigned in the
|
||||||
// function call take the value provided.
|
// function call take their provided value.
|
||||||
// - All named arguments which were not provided by the user are
|
// - Then, any positional arguments are assigned to remaining unassigned
|
||||||
// affected from positional arguments; the priority order in which
|
// parameters; this is governed both by the `priority` entries
|
||||||
// these are assigned is given by the `priority` argument, while the
|
// (if there are `N` positional arguments, then the `N` parameters with
|
||||||
// positional assignation is done in the order of the named arguments.
|
// lowest `priority` value will be assigned) and by the order of the
|
||||||
// - Any remaining named arguments take the provided default values.
|
// positional arguments (matching that of the assigned named parameters).
|
||||||
// If only k positional arguments are used, then the k named values
|
// If no priority is given, then these two ordering coincide:
|
||||||
// with lowest 'priority' value (among the unassigned ones) will get them.
|
// parameters are assigned in order, starting from the first one.
|
||||||
// The arguments will be assigned in the order of the named values.
|
// - Finally, any remaining named parameters can take default values.
|
||||||
// By default these two orders coincide.
|
// If no default values are given, then `undef` is used.
|
||||||
|
// .
|
||||||
|
// This allows an author to declare a function prototype with named or
|
||||||
|
// optional parameters, so that the user may then call this function
|
||||||
|
// using either positional or named parameters. In practice the author
|
||||||
|
// will declare the function as using *both* positional and named
|
||||||
|
// parameters, and let `get_named_args()` do the parsing from the whole
|
||||||
|
// set of arguments.
|
||||||
|
// See the example below.
|
||||||
|
// .
|
||||||
|
// This supports the user explicitly passing `undef` as a function argument.
|
||||||
|
// To distinguish between an intentional `undef` and
|
||||||
|
// the absence of an argument, we use a custom `_undef` value
|
||||||
|
// as a guard marking the absence of any arguments
|
||||||
|
// (in practice, `_undef` is a random-generated string,
|
||||||
|
// which will never coincide with any useful user value).
|
||||||
|
// This forces the author to declare all the function parameters
|
||||||
|
// as having `_undef` as their default value.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// positional = the list of values of positional arguments.
|
// 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.
|
// 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 (lower means more priority, default value is `+inf`). Since stable sorting is used, if no priority at all is given, all arguments will be read in order.
|
||||||
// _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).
|
// _undef = the default value used by the calling function for all arguments. The default value, `_undef`, is a random string. This value **must** be the default value of all parameters in the outer function call (see example below).
|
||||||
//
|
//
|
||||||
//
|
// Example: a function with prototype `f(named1,< <named2>, named3 >)`
|
||||||
//
|
// function f(_p1=_undef, _p2=_undef, _p3=_undef,
|
||||||
// Examples:
|
// arg1=_undef, arg2=_undef, arg3=_undef) =
|
||||||
// function f(arg1=_undef, arg2=_undef, arg3=_undef, named1=_undef, named2=_undef, named3=_undef) = let(named = get_named_args([arg1, arg2, arg3], [[named1, "default1"], [named2, "default2"], [named3, "default3"]])) named;
|
// let(named = get_named_args([_p1, _p2, _p3],
|
||||||
// echo(f()); // ["default1", "default2", "default3"]
|
// [[arg1, "default1",0], [arg2, "default2",2], [arg3, "default3",1]]))
|
||||||
// echo(f("given2", "given3", named1="given1")); // ["given1", "given2", "given3"]
|
// named;
|
||||||
// echo(f("given1")); // ["given1", "default2", "default3"]
|
// // all default values or all parameters provided:
|
||||||
// echo(f(named1="given1", "given2")); // ["given1", "given2", "default3"]
|
// echo(f());
|
||||||
// echo(f(undef, named1="given1", undef)); // ["given1", undef, undef]
|
// // ["default1", "default2", "default3"]
|
||||||
|
// echo(f("given2", "given3", arg1="given1"));
|
||||||
|
// // ["given1", "given2", "given3"]
|
||||||
|
//
|
||||||
|
// // arg1 has highest priority, and arg3 is higher than arg2:
|
||||||
|
// echo(f("given1"));
|
||||||
|
// // ["given1", "default2", "default3"]
|
||||||
|
// echo(f("given3", arg1="given1"));
|
||||||
|
// // ["given1", "default2", "given3"]
|
||||||
|
//
|
||||||
|
// // explicitly passing undef is allowed:
|
||||||
|
// echo(f(undef, arg1="given1", undef));
|
||||||
|
// // ["given1", undef, undef]
|
||||||
|
|
||||||
// a value that the user should never enter randomly;
|
// a value that the user should never enter randomly;
|
||||||
// result of `dd if=/dev/random bs=32 count=1 |base64` :
|
// result of `dd if=/dev/random bs=32 count=1 |base64` :
|
||||||
|
@ -366,7 +395,8 @@ function get_named_args(positional, named,_undef=_undef) =
|
||||||
// those elements which have no priority assigned go last (prio=+∞):
|
// those elements which have no priority assigned go last (prio=+∞):
|
||||||
prio = sortidx([for(u=unknown) default(named[u][2], 1/0)]),
|
prio = sortidx([for(u=unknown) default(named[u][2], 1/0)]),
|
||||||
// list of indices of values assigned from positional arguments:
|
// list of indices of values assigned from positional arguments:
|
||||||
assigned = sort([for(i=[0:1:n_positional-1]) prio[i]]))
|
assigned = [for(a=sort([for(i=[0:1:n_positional-1]) prio[i]]))
|
||||||
|
unknown[a]])
|
||||||
[ for(e = enumerate(named))
|
[ for(e = enumerate(named))
|
||||||
let(idx=e[0], val=e[1][0], ass=search(idx, assigned))
|
let(idx=e[0], val=e[1][0], ass=search(idx, assigned))
|
||||||
val != _undef ? val :
|
val != _undef ? val :
|
||||||
|
|
|
@ -67,17 +67,17 @@ module bounding_box(excess=0) {
|
||||||
// Function&Module: half_of()
|
// Function&Module: half_of()
|
||||||
//
|
//
|
||||||
// Usage: as module
|
// Usage: as module
|
||||||
// half_of(v, [cp], [s]) ...
|
// half_of(v, <cp>, <s>) ...
|
||||||
// Usage: as function
|
// Usage: as function
|
||||||
// half_of(v, [cp], p, [s])...
|
// half_of(v, <cp>, p, <s>)...
|
||||||
//
|
//
|
||||||
// Description:
|
// Description:
|
||||||
// Slices an object at a cut plane, and masks away everything that is on one side.
|
// Slices an object at a cut plane, and masks away everything that is on one side.
|
||||||
// * Called as a function with a path in the `p` argument, returns the
|
// * Called as a function with a path in the `p` argument, returns the
|
||||||
// intersection of path `p` and given half-space.
|
// intersection of path `p` and given half-space.
|
||||||
// * Called as a function with a 2D path in the `p` argument
|
// * Called as a function with a 2D path in the `p` argument
|
||||||
// and a 2D vector `p`, returns the intersection of path `p` and given
|
// and a 2D vector `p`, returns the intersection of path `p` and given
|
||||||
// half-plane.
|
// half-plane.
|
||||||
//
|
//
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// v = Normal of plane to slice at. Keeps everything on the side the normal points to. Default: [0,0,1] (UP)
|
// v = Normal of plane to slice at. Keeps everything on the side the normal points to. Default: [0,0,1] (UP)
|
||||||
|
@ -121,7 +121,7 @@ module half_of(v=UP, cp, s=1000, planar=false)
|
||||||
function half_of(_arg1=_undef, _arg2=_undef, _arg3=_undef, _arg4=_undef,
|
function half_of(_arg1=_undef, _arg2=_undef, _arg3=_undef, _arg4=_undef,
|
||||||
v=_undef, cp=_undef, p=_undef, s=_undef) =
|
v=_undef, cp=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3, _arg4],
|
let(args=get_named_args([_arg1, _arg2, _arg3, _arg4],
|
||||||
[[v,undef,0], [cp,0,2], [p,undef,1], [s,1e4,3]]),
|
[[v,undef,0], [cp,0,2], [p,undef,1], [s, 1e4]]),
|
||||||
v=args[0], cp0=args[1], p=args[2], s=args[3],
|
v=args[0], cp0=args[1], p=args[2], s=args[3],
|
||||||
cp = is_num(cp0) ? cp0*unit(v) : cp0)
|
cp = is_num(cp0) ? cp0*unit(v) : cp0)
|
||||||
assert(is_vector(v,2)||is_vector(v,3),
|
assert(is_vector(v,2)||is_vector(v,3),
|
||||||
|
@ -160,12 +160,12 @@ function half_of(_arg1=_undef, _arg2=_undef, _arg3=_undef, _arg4=_undef,
|
||||||
// Function&Module: left_half()
|
// Function&Module: left_half()
|
||||||
//
|
//
|
||||||
// Usage: as module
|
// Usage: as module
|
||||||
// left_half([s], [x]) ...
|
// left_half(<s>, <x>) ...
|
||||||
// left_half(planar=true, [s], [x]) ...
|
// left_half(planar=true, <s>, <x>) ...
|
||||||
// Usage: as function
|
// Usage: as function
|
||||||
// left_half([s], [x], path)
|
// left_half(<s>, <x>, path)
|
||||||
// left_half([s], [x], region)
|
// left_half(<s>, <x>, region)
|
||||||
// left_half([s], [x], vnf)
|
// left_half(<s>, <x>, vnf)
|
||||||
//
|
//
|
||||||
// Description:
|
// Description:
|
||||||
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is right of it.
|
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is right of it.
|
||||||
|
@ -197,7 +197,7 @@ module left_half(s=1000, x=0, planar=false)
|
||||||
function left_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
function left_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
x=_undef, p=_undef, s=_undef) =
|
x=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3],
|
let(args=get_named_args([_arg1, _arg2, _arg3],
|
||||||
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
|
[[x, 0,1], [p,undef,0], [s, 1e4]]),
|
||||||
x=args[0], p=args[1], s=args[2])
|
x=args[0], p=args[1], s=args[2])
|
||||||
half_of(v=[1,0,0], cp=x, p=p);
|
half_of(v=[1,0,0], cp=x, p=p);
|
||||||
|
|
||||||
|
@ -209,6 +209,7 @@ function left_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
// right_half([s], [x]) ...
|
// right_half([s], [x]) ...
|
||||||
// right_half(planar=true, [s], [x]) ...
|
// right_half(planar=true, [s], [x]) ...
|
||||||
//
|
//
|
||||||
|
//
|
||||||
// Description:
|
// Description:
|
||||||
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is left of it.
|
// Slices an object at a vertical Y-Z cut plane, and masks away everything that is left of it.
|
||||||
//
|
//
|
||||||
|
@ -239,7 +240,7 @@ module right_half(s=1000, x=0, planar=false)
|
||||||
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
x=_undef, p=_undef, s=_undef) =
|
x=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3],
|
let(args=get_named_args([_arg1, _arg2, _arg3],
|
||||||
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
|
[[x, 0,1], [p,undef,0], [s, 1e4]]),
|
||||||
x=args[0], p=args[1], s=args[2])
|
x=args[0], p=args[1], s=args[2])
|
||||||
half_of(v=[-1,0,0], cp=x, p=p);
|
half_of(v=[-1,0,0], cp=x, p=p);
|
||||||
|
|
||||||
|
@ -281,7 +282,7 @@ module front_half(s=1000, y=0, planar=false)
|
||||||
function front_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
function front_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
x=_undef, p=_undef, s=_undef) =
|
x=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3],
|
let(args=get_named_args([_arg1, _arg2, _arg3],
|
||||||
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
|
[[x, 0,1], [p,undef,0], [s, 1e4]]),
|
||||||
x=args[0], p=args[1], s=args[2])
|
x=args[0], p=args[1], s=args[2])
|
||||||
half_of(v=[0,1,0], cp=x, p=p);
|
half_of(v=[0,1,0], cp=x, p=p);
|
||||||
|
|
||||||
|
@ -323,7 +324,7 @@ module back_half(s=1000, y=0, planar=false)
|
||||||
function back_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
function back_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
x=_undef, p=_undef, s=_undef) =
|
x=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3],
|
let(args=get_named_args([_arg1, _arg2, _arg3],
|
||||||
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
|
[[x, 0,1], [p,undef,0], [s, 1e4]]),
|
||||||
x=args[0], p=args[1], s=args[2])
|
x=args[0], p=args[1], s=args[2])
|
||||||
half_of(v=[0,-1,0], cp=x, p=p);
|
half_of(v=[0,-1,0], cp=x, p=p);
|
||||||
|
|
||||||
|
@ -357,7 +358,7 @@ module bottom_half(s=1000, z=0)
|
||||||
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
x=_undef, p=_undef, s=_undef) =
|
x=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3],
|
let(args=get_named_args([_arg1, _arg2, _arg3],
|
||||||
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
|
[[x, 0,1], [p,undef,0], [s, 1e4]]),
|
||||||
x=args[0], p=args[1], s=args[2])
|
x=args[0], p=args[1], s=args[2])
|
||||||
half_of(v=[0,0,-1], cp=x, p=p);
|
half_of(v=[0,0,-1], cp=x, p=p);
|
||||||
|
|
||||||
|
@ -391,7 +392,7 @@ module top_half(s=1000, z=0)
|
||||||
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
function right_half(_arg1=_undef, _arg2=_undef, _arg3=_undef,
|
||||||
x=_undef, p=_undef, s=_undef) =
|
x=_undef, p=_undef, s=_undef) =
|
||||||
let(args=get_named_args([_arg1, _arg2, _arg3],
|
let(args=get_named_args([_arg1, _arg2, _arg3],
|
||||||
[[x, 0,1], [p,undef,0], [s, 1e4,2]]),
|
[[x, 0,1], [p,undef,0], [s, 1e4]]),
|
||||||
x=args[0], p=args[1], s=args[2])
|
x=args[0], p=args[1], s=args[2])
|
||||||
half_of(v=[0,0,1], cp=x, p=p);
|
half_of(v=[0,0,1], cp=x, p=p);
|
||||||
|
|
||||||
|
|
13
vnf.scad
13
vnf.scad
|
@ -829,14 +829,14 @@ module vnf_validate(vnf, size=1, show_warns=true, check_isects=false) {
|
||||||
|
|
||||||
// Section: VNF transformations
|
// Section: VNF transformations
|
||||||
//
|
//
|
||||||
|
|
||||||
// Function: vnf_halfspace(halfspace, vnf)
|
// Function: vnf_halfspace(halfspace, vnf)
|
||||||
// Usage:
|
// Usage:
|
||||||
// vnf_halfspace([a,b,c,d], vnf)
|
// vnf_halfspace([a,b,c,d], vnf)
|
||||||
// Description:
|
// Description:
|
||||||
// returns the intersection of the VNF with the given half-space.
|
// returns the intersection of the VNF with the given half-space.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// halfspace = half-space to intersect with, given as the four
|
// halfspace = half-space to intersect with, given as the four coefficients of the affine inequation a\*x+b\*y+c\*z≥ d.
|
||||||
// coefficients of the affine inequation a*x+b*y+c*z+d ≥ 0.
|
|
||||||
|
|
||||||
function _vnf_halfspace_pts(halfspace, points, faces,
|
function _vnf_halfspace_pts(halfspace, points, faces,
|
||||||
inside=undef, coords=[], map=[]) =
|
inside=undef, coords=[], map=[]) =
|
||||||
|
@ -861,7 +861,7 @@ function _vnf_halfspace_pts(halfspace, points, faces,
|
||||||
// termination test:
|
// termination test:
|
||||||
i >= len(points) ? [ coords, map, inside ] :
|
i >= len(points) ? [ coords, map, inside ] :
|
||||||
let(inside = !is_undef(inside) ? inside :
|
let(inside = !is_undef(inside) ? inside :
|
||||||
[for(x=points) halfspace*concat(x,[1]) >= 0],
|
[for(x=points) halfspace*concat(x,[-1]) >= 0],
|
||||||
pi = points[i])
|
pi = points[i])
|
||||||
// inside half-space: keep the point (and reindex)
|
// inside half-space: keep the point (and reindex)
|
||||||
inside[i] ? _vnf_halfspace_pts(halfspace, points, faces, inside,
|
inside[i] ? _vnf_halfspace_pts(halfspace, points, faces, inside,
|
||||||
|
@ -871,10 +871,10 @@ function _vnf_halfspace_pts(halfspace, points, faces,
|
||||||
each if(j!=undef) [f[(j+1)%m], f[(j+m-1)%m]] ]),
|
each if(j!=undef) [f[(j+1)%m], f[(j+m-1)%m]] ]),
|
||||||
// filter those which lie in half-space:
|
// filter those which lie in half-space:
|
||||||
adj2 = [for(x=adj) if(inside[x]) x],
|
adj2 = [for(x=adj) if(inside[x]) x],
|
||||||
zi = halfspace*concat(pi, [1]))
|
zi = halfspace*concat(pi, [-1]))
|
||||||
_vnf_halfspace_pts(halfspace, points, faces, inside,
|
_vnf_halfspace_pts(halfspace, points, faces, inside,
|
||||||
// new points: we append all these intersection points
|
// new points: we append all these intersection points
|
||||||
concat(coords, [for(j=adj2) let(zj=halfspace*concat(points[j],[1]))
|
concat(coords, [for(j=adj2) let(zj=halfspace*concat(points[j],[-1]))
|
||||||
(zi*points[j]-zj*pi)/(zi-zj)]),
|
(zi*points[j]-zj*pi)/(zi-zj)]),
|
||||||
// map: we add the info
|
// map: we add the info
|
||||||
concat(map, [[for(y=enumerate(adj2)) [y[1], n+y[0]]]]));
|
concat(map, [[for(y=enumerate(adj2)) [y[1], n+y[0]]]]));
|
||||||
|
@ -950,7 +950,4 @@ function vnf_halfspace(_arg1=_undef, _arg2=_undef,
|
||||||
loops=[for(p=paths) if(p[0] == last(p)) p])
|
loops=[for(p=paths) if(p[0] == last(p)) p])
|
||||||
[coords, concat(newfaces, loops)];
|
[coords, concat(newfaces, loops)];
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
//
|
|
||||||
|
|
Loading…
Reference in a new issue