From a13a09db8d61985a552cf5a4a142dbd1a02e236f Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Thu, 28 Jan 2021 16:59:46 -0800 Subject: [PATCH] Docs cleanup for common.scad --- bottlecaps.scad | 13 ++ common.scad | 347 ++++++++++++++++++++++++++++------------- rounding.scad | 8 +- tests/test_common.scad | 21 +-- version.scad | 2 +- 5 files changed, 257 insertions(+), 134 deletions(-) diff --git a/bottlecaps.scad b/bottlecaps.scad index 099e51c..1c8b901 100644 --- a/bottlecaps.scad +++ b/bottlecaps.scad @@ -131,6 +131,9 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP) } } +function pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP) = + no_function("pco1810_neck"); + // Module: pco1810_cap() // Usage: @@ -195,6 +198,10 @@ module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) } } +function pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) = + no_function("pco1810_cap"); + + // Section: PCO-1881 Bottle Threading @@ -316,6 +323,9 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP) } } +function pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP) = + no_function("pco1881_neck"); + // Module: pco1881_cap() // Usage: @@ -372,6 +382,9 @@ module pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) } } +function pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) = + no_function("pco1881_cap"); + // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/common.scad b/common.scad index e624205..b02b240 100644 --- a/common.scad +++ b/common.scad @@ -13,8 +13,17 @@ // Usage: // typ = typeof(x); // Description: -// Returns a string representing the type of the value. One of "undef", "boolean", "number", "nan", "string", "list", "range" or "invalid". +// Returns a string representing the type of the value. One of "undef", "boolean", "number", "nan", "string", "list", "range", "function" or "invalid". // Some malformed "ranges", like '[0:NAN:INF]' and '[0:"a":INF]', may be classified as "undef" or "invalid". +// Examples: +// typ = typeof(undef); // Returns: "undef" +// typ = typeof(true); // Returns: "boolean" +// typ = typeof(42); // Returns: "number" +// typ = typeof(NAN); // Returns: "nan" +// typ = typeof("foo"); // Returns: "string" +// typ = typeof([3,4,5]); // Returns: "list" +// typ = typeof([3:1:8]); // Returns: "range" +// typ = typeof(function (x,y) x+y); // Returns: "function" function typeof(x) = is_undef(x)? "undef" : is_bool(x)? "boolean" : @@ -23,16 +32,17 @@ function typeof(x) = is_string(x)? "string" : is_list(x)? "list" : is_range(x) ? "range" : + version_num()>20210000 && is_function(x) ? "function" : "invalid"; // Function: is_type() // Usage: -// b = is_type(x, types); +// bool = is_type(x, types); // Description: // Returns true if the type of the value `x` is one of those given as strings in the list `types`. -// Valid types are "undef", "boolean", "number", "nan", "string", "list", or "range" +// Valid types are "undef", "boolean", "number", "nan", "string", "list", "range", or "function". // Arguments: // x = The value to check the type of. // types = A list of types to check @@ -52,54 +62,103 @@ function is_type(x,types) = // Function: is_def() // Usage: -// is_def(x) +// bool = is_def(x); // Description: // Returns true if `x` is not `undef`. False if `x==undef`. +// Example: +// bool = is_def(undef); // Returns: false +// bool = is_def(false); // Returns: true +// bool = is_def(42); // Returns: true +// bool = is_def("foo"); // Returns: true function is_def(x) = !is_undef(x); // Function: is_str() // Usage: -// is_str(x) +// bool = is_str(x); // Description: // Returns true if `x` is a string. A shortcut for `is_string()`. +// Example: +// bool = is_str(undef); // Returns: false +// bool = is_str(false); // Returns: false +// bool = is_str(42); // Returns: false +// bool = is_str("foo"); // Returns: true function is_str(x) = is_string(x); // Function: is_int() // Usage: -// is_int(n) +// bool = is_int(n); +// bool = is_integer(n); // Description: // Returns true if the given value is an integer (it is a number and it rounds to itself). +// Example: +// bool = is_int(undef); // Returns: false +// bool = is_int(false); // Returns: false +// bool = is_int(42); // Returns: true +// bool = is_int("foo"); // Returns: false function is_int(n) = is_finite(n) && n == round(n); function is_integer(n) = is_finite(n) && n == round(n); // Function: is_nan() // Usage: -// is_nan(x); +// bool = is_nan(x); // Description: // Returns true if a given value `x` is nan, a floating point value representing "not a number". +// Example: +// bool = is_nan(undef); // Returns: false +// bool = is_nan(false); // Returns: false +// bool = is_nan(42); // Returns: false +// bool = is_nan("foo"); // Returns: false +// bool = is_nan(NAN); // Returns: true function is_nan(x) = (x!=x); // Function: is_finite() // Usage: -// is_finite(x); +// bool = is_finite(x); // Description: // Returns true if a given value `x` is a finite number. +// Example: +// bool = is_finite(undef); // Returns: false +// bool = is_finite(false); // Returns: false +// bool = is_finite(42); // Returns: true +// bool = is_finite("foo"); // Returns: false +// bool = is_finite(NAN); // Returns: false +// bool = is_finite(INF); // Returns: false +// bool = is_finite(-INF); // Returns: false function is_finite(x) = is_num(x) && !is_nan(0*x); // Function: is_range() +// Usage: +// bool = is_range(x); // Description: // Returns true if its argument is a range +// Example: +// bool = is_range(undef); // Returns: false +// bool = is_range(false); // Returns: false +// bool = is_range(42); // Returns: false +// bool = is_range([3,4,5]); // Returns: false +// bool = is_range("foo"); // Returns: false +// bool = is_range([3:5]); // Returns: true function is_range(x) = !is_list(x) && is_finite(x[0]) && is_finite(x[1]) && is_finite(x[2]) ; // Function: valid_range() +// Usage: +// bool = valid_range(x); // Description: // Returns true if its argument is a valid range (deprecated ranges excluded). +// Example: +// bool = is_range(undef); // Returns: false +// bool = is_range(false); // Returns: false +// bool = is_range(42); // Returns: false +// bool = is_range([3,4,5]); // Returns: false +// bool = is_range("foo"); // Returns: false +// bool = is_range([3:5]); // Returns: true +// bool = is_range([3:1]); // Returns: false function valid_range(x) = is_range(x) && ( x[1]>0 @@ -109,7 +168,7 @@ function valid_range(x) = // Function: is_list_of() // Usage: -// is_list_of(list, pattern) +// bool = is_list_of(list, pattern); // Description: // Tests whether the input is a list whose entries are all numeric lists that have the same // list shape as the pattern. @@ -130,7 +189,7 @@ function is_list_of(list,pattern) = // Function: is_consistent() // Usage: -// is_consistent(list) +// bool = is_consistent(list); // Description: // Tests whether input is a list of entries which all have the same list structure // and are filled with finite numerical data. It returns `true`for the empty list. @@ -154,7 +213,7 @@ function _list_pattern(list) = // Function: same_shape() // Usage: -// same_shape(a,b) +// bool = same_shape(a,b); // Description: // Tests whether the inputs `a` and `b` are both numeric and are the same shaped list. // Example: @@ -167,9 +226,10 @@ function same_shape(a,b) = _list_pattern(a) == b*0; // Function: default() +// Usage: +// val = default(val, dflt); // Description: -// Returns the value given as `v` if it is not `undef`. -// Otherwise, returns the value of `dflt`. +// Returns the value given as `v` if it is not `undef`. Otherwise, returns the value of `dflt`. // Arguments: // v = Value to pass through if not `undef`. // dflt = Value to return if `v` *is* `undef`. @@ -177,6 +237,8 @@ function default(v,dflt=undef) = is_undef(v)? dflt : v; // Function: first_defined() +// Usage: +// val = first_defined(v, ); // Description: // Returns the first item in the list that is not `undef`. // If all items are `undef`, or list is empty, returns `undef`. @@ -195,42 +257,86 @@ function first_defined(v,recursive=false,_i=0) = // Function: one_defined() // Usage: -// one_defined(vars, names, ) +// val = one_defined(vals, names, ) // Description: -// Examines the input list `vars` and returns the entry which is not `undef`. If more -// than one entry is `undef` then issues an assertion specifying "Must define exactly one of" followed -// by the defined items from the `names` parameter. If `required` is set to false then it is OK if all of the -// entries of `vars` are undefined, and in this case, `undef` is returned. -// Example: +// Examines the input list `vals` and returns the entry which is not `undef`. +// If more than one entry is not `undef` then an error is asserted, specifying +// "Must define exactly one of" followed by the names in the `names` parameter. +// If `dflt` is given, and all `vals` are `undef`, then the value in `dflt` is returned. +// If `dflt` is *not* given, and all `vals` are `undef`, then an error is asserted. +// Arguments: +// vals = The values to return the first one which is not `undef`. +// names = A string with comma-separated names for the arguments whose values are passed in `vals`. +// dflt = If given, the value returned if all `vals` are `undef`. +// Examples: // length = one_defined([length,L,l], ["length","L","l"]); -function one_defined(vars, names, required=true) = - assert(len(vars)==len(names)) - let ( - ok = num_defined(vars)==1 || (!required && num_defined(vars)==0) - ) - assert(ok,str("Must define ",required?"exactly":"at most"," one of ",num_defined(vars)==0?names:[for(i=[0:len(vars)]) if (is_def(vars[i])) names[i]])) - first_defined(vars); +// length = one_defined([length,L,l], "length,L,l", dflt=1); +function one_defined(vals, names, dflt=_undef) = + let( + checkargs = is_list(names)? assert(len(vals) == len(names)) : + is_string(names)? let( + name_cnt = len([for (c=names) if (c==",") 1]) + 1 + ) assert(len(vals) == name_cnt) : + assert(is_list(names) || is_string(names)) 0, + ok = num_defined(vals)==1 || (dflt!=_undef && num_defined(vals)==0) + ) ok? default(first_defined(vals), dflt) : + let( + names = is_string(names) ? str_split(names,",") : names, + defd = [for (i=idx(vals)) if (is_def(vals[i])) names[i]], + msg = str( + "Must define ", + dflt==_undef? "exactly" : "at most", + " one of ", + num_defined(vals) == 0 ? names : defd + ) + ) assert(ok,msg); // Function: num_defined() -// Description: Counts how many items in list `v` are not `undef`. -function num_defined(v) = len([for(vi=v) if(!is_undef(vi)) 1]); +// Usage: +// cnt = num_defined(v); +// Description: +// Counts how many items in list `v` are not `undef`. +// Example: +// cnt = num_defined([3,7,undef,2,undef,undef,1]); // Returns: 4 +function num_defined(v) = + len([for(vi=v) if(!is_undef(vi)) 1]); + // Function: any_defined() +// Usage: +// bool = any_defined(v, ); // Description: // Returns true if any item in the given array is not `undef`. // Arguments: // v = The list whose items are being checked. // recursive = If true, any sublists are evaluated recursively. -function any_defined(v,recursive=false) = first_defined(v,recursive=recursive) != undef; +// Example: +// bool = any_defined([undef,undef,undef]); // Returns: false +// bool = any_defined([undef,42,undef]); // Returns: true +// bool = any_defined([34,42,87]); // Returns: true +// bool = any_defined([undef,undef,[undef]]); // Returns: true +// bool = any_defined([undef,undef,[undef]],recursive=true); // Returns: false +// bool = any_defined([undef,undef,[42]],recursive=true); // Returns: true +function any_defined(v,recursive=false) = + first_defined(v,recursive=recursive) != undef; // Function: all_defined() +// Usage: +// bool = all_defined(v, ); // Description: // Returns true if all items in the given array are not `undef`. // Arguments: // v = The list whose items are being checked. // recursive = If true, any sublists are evaluated recursively. +// Example: +// bool = all_defined([undef,undef,undef]); // Returns: false +// bool = all_defined([undef,42,undef]); // Returns: false +// bool = all_defined([34,42,87]); // Returns: true +// bool = all_defined([23,34,[undef]]); // Returns: true +// bool = all_defined([23,34,[undef]],recursive=true); // Returns: false +// bool = all_defined([23,34,[42]],recursive=true); // Returns: true function all_defined(v,recursive=false) = []==[for (x=v) if(is_undef(x)||(recursive && is_list(x) && !all_defined(x,recursive))) 0 ]; @@ -241,7 +347,7 @@ function all_defined(v,recursive=false) = // Function: get_anchor() // Usage: -// get_anchor(anchor,center,,); +// anchr = get_anchor(anchor,center,,); // Description: // Calculated the correct anchor from `anchor` and `center`. In order: // - If `center` is not `undef` and `center` evaluates as true, then `CENTER` (`[0,0,0]`) is returned. @@ -254,6 +360,13 @@ function all_defined(v,recursive=false) = // center = If not `undef`, this overrides the value of `anchor`. // uncentered = The value to return if `center` is not `undef` and evaluates as false. Default: ALLNEG // dflt = The default value to return if both `anchor` and `center` are `undef`. Default: `CENTER` +// Examples: +// anchr = get_anchor(undef, undef, BOTTOM, TOP); // Returns: [0, 0, 1] (TOP) +// anchr = get_anchor(RIGHT, undef, BOTTOM, TOP); // Returns: [1, 0, 0] (RIGHT) +// anchr = get_anchor(undef, false, BOTTOM, TOP); // Returns: [0, 0,-1] (BOTTOM) +// anchr = get_anchor(RIGHT, false, BOTTOM, TOP); // Returns: [0, 0,-1] (BOTTOM) +// anchr = get_anchor(undef, true, BOTTOM, TOP); // Returns: [0, 0, 0] (CENTER) +// anchr = get_anchor(RIGHT, true, BOTTOM, TOP); // Returns: [0, 0, 0] (CENTER) function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) = !is_undef(center)? (center? CENTER : uncentered) : !is_undef(anchor)? anchor : @@ -262,24 +375,35 @@ function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) = // Function: get_radius() // Usage: -// get_radius(, , , , , , ); +// r = get_radius(, , , , , , ); // Description: -// Given various radii and diameters, returns the most specific radius. -// If a diameter is most specific, returns half its value, giving the radius. -// If no radii or diameters are defined, returns the value of dflt. -// Value specificity order is r1, r2, d1, d2, r, d, then dflt -// Only one of `r1`, `r2`, `d1`, or `d2` can be defined at once, or else it -// errors out, complaining about conflicting radius/diameter values. -// Only one of `r` or `d` can be defined at once, or else it errors out, -// complaining about conflicting radius/diameter values. +// Given various radii and diameters, returns the most specific radius. If a diameter is most +// specific, returns half its value, giving the radius. If no radii or diameters are defined, +// returns the value of `dflt`. Value specificity order is `r1`, `r2`, `d1`, `d2`, `r`, `d`, +// then `dflt`. Only one of `r1`, `r2`, `d1`, or `d2` can be defined at once, or else it errors +// out, complaining about conflicting radius/diameter values. Only one of `r` or `d` can be +// defined at once, or else it errors out, complaining about conflicting radius/diameter values. // Arguments: +// --- // r1 = Most specific radius. -// d1 = Most specific diameter. // r2 = Second most specific radius. -// d2 = Second most specific diameter. // r = Most general radius. +// d1 = Most specific diameter. +// d2 = Second most specific diameter. // d = Most general diameter. // dflt = Value to return if all other values given are `undef`. +// Examples: +// r = get_radius(r1=undef, r=undef, dflt=undef); // Returns: undef +// r = get_radius(r1=undef, r=undef, dflt=1); // Returns: 1 +// r = get_radius(r1=undef, r=6, dflt=1); // Returns: 6 +// r = get_radius(r1=7, r=6, dflt=1); // Returns: 7 +// r = get_radius(r1=undef, r2=8, r=6, dflt=1); // Returns: 8 +// r = get_radius(r1=undef, r2=8, d=6, dflt=1); // Returns: 8 +// r = get_radius(r1=undef, d=6, dflt=1); // Returns: 3 +// r = get_radius(d1=7, d=6, dflt=1); // Returns: 3.5 +// r = get_radius(d1=7, d2=8, d=6, dflt=1); // Returns: 3.5 +// r = get_radius(d1=undef, d2=8, d=6, dflt=1); // Returns: 4 +// r = get_radius(r1=8, d=6, dflt=1); // Returns: 8 function get_radius(r1, r2, r, d1, d2, d, dflt) = assert(num_defined([r1,d1,r2,d2])<2, "Conflicting or redundant radius/diameter arguments given.") !is_undef(r1) ? assert(is_finite(r1), "Invalid radius r1." ) r1 @@ -294,61 +418,37 @@ function get_radius(r1, r2, r, d1, d2, d, dflt) = : dflt; -// Function: get_height() -// Usage: -// get_height(,,,) -// Description: -// Given several different parameters for height check that height is not multiply defined -// and return a single value. If the three values `l`, `h`, and `height` are all undefined -// then return the value `dflt`, if given, or undef otherwise. -// Arguments: -// l = l. -// h = h. -// height = height. -// dflt = Value to return if other values are `undef`. -function get_height(h,l,height,dflt) = - 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() // 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], ...) // Description: -// Given the values of some positional and named arguments, -// returns a list of the values assigned to named parameters. -// in the following steps: -// - First, all named parameters which were explicitly assigned in the -// function call take their provided value. +// Given the values of some positional and named arguments, returns a list of the values assigned to +// named parameters. in the following steps: +// - First, all named parameters which were explicitly assigned in the function call take their +// provided value. // - Then, any positional arguments are assigned to remaining unassigned -// parameters; this is governed both by the `priority` entries -// (if there are `N` positional arguments, then the `N` parameters with -// lowest `priority` value will be assigned) and by the order of the -// positional arguments (matching that of the assigned named parameters). -// If no priority is given, then these two ordering coincide: -// parameters are assigned in order, starting from the first one. -// - Finally, any remaining named parameters can take default values. -// If no default values are given, then `undef` is used. +// parameters; this is governed both by the `priority` entries (if there are `N` positional +// arguments, then the `N` parameters with lowest `priority` value will be assigned) and by the +// order of the positional arguments (matching that of the assigned named parameters). If no +// priority is given, then these two ordering coincide: parameters are assigned in order, starting +// from the first one. +// - Finally, any remaining named parameters can take default values. 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 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. +// 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: -// positional = the list of values of positional arguments. -// named = the list of named arguments; each entry of the list has the form `[passed-value, , ]`, 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. 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). +// positional = The list of values of positional arguments. +// named = The list of named arguments; each entry of the list has the form `[passed-value, , ]`, 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. 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,< , named3 >)` // function f(_p1=_undef, _p2=_undef, _p3=_undef, @@ -404,7 +504,7 @@ function get_named_args(positional, named,_undef=_undef) = // Function: scalar_vec3() // Usage: -// scalar_vec3(v, ); +// vec = scalar_vec3(v, ); // Description: // If `v` is a scalar, and `dflt==undef`, returns `[v, v, v]`. // If `v` is a scalar, and `dflt!=undef`, returns `[v, dflt, dflt]`. @@ -413,7 +513,12 @@ function get_named_args(positional, named,_undef=_undef) = // Arguments: // v = Value to return vector from. // dflt = Default value to set empty vector parts from. -function scalar_vec3(v, dflt=undef) = +// Examples: +// vec = scalar_vec3(undef); // Returns: undef +// vec = scalar_vec3(10); // Returns: [10,10,10] +// vec = scalar_vec3(10,1); // Returns: [10,1,1] +// vec = scalar_vec3([10,10],1); // Returns: [10,10,1] +function scalar_vec3(v, dflt) = is_undef(v)? undef : is_list(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] : !is_undef(dflt)? [v,dflt,dflt] : [v,v,v]; @@ -426,11 +531,13 @@ function scalar_vec3(v, dflt=undef) = // Calculate the standard number of sides OpenSCAD would give a circle based on `$fn`, `$fa`, and `$fs`. // Arguments: // r = Radius of circle to get the number of segments for. +// Examples: +// $fn=12; sides=segs(10); // Returns: 12 +// $fa=2; $fs=3, sides=segs(10); // Returns: 21 function segs(r) = $fn>0? ($fn>3? $fn : 3) : - let( r = is_finite(r)? r: 0 ) - ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs))) ; - + let( r = is_finite(r)? r : 0 ) + ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs))); // Module: no_children() @@ -441,18 +548,22 @@ function segs(r) = // as indicated by its argument. // Arguments: // $children = number of children the module has. +// Example: +// no_children($children); module no_children(count) { assert($children==0, "Module no_children() does not support child modules"); assert(count==0, str("Module ",parent_module(1),"() does not support child modules")); } + + // Function: no_function() // Usage: // dummy = no_function(name) // Description: // Asserts that the function, "name", only exists as a module. // Example: -// +// x = no_function("foo"); function no_function(name) = assert(false,str("You called ",name,"() as a function, but it is available only as a module")); @@ -462,6 +573,8 @@ function no_function(name) = // no_module(); // Description: // Asserts that the called module exists only as a function. +// Example: +// no_module(); module no_module() { assert(false, str("You called ",parent_module(1),"() as a module but it is available only as a function")); } @@ -486,6 +599,8 @@ function _valstr(x) = // got = The value actually received. // expected = The value that was expected. // info = Extra info to print out to make the error clearer. +// Example: +// assert_approx(1/3, 0.333333333333333, str("numer=",1,", demon=",3)); module assert_approx(got, expected, info) { no_children($children); if (!approx(got, expected)) { @@ -507,13 +622,14 @@ module assert_approx(got, expected, info) { // Usage: // assert_equal(got, expected, ); // Description: -// Tests if the value gotten is what was expected. If not, then -// the expected and received values are printed to the console and -// an assertion is thrown to stop execution. +// Tests if the value gotten is what was expected. If not, then the expected and received values +// are printed to the console and an assertion is thrown to stop execution. // Arguments: // got = The value actually received. // expected = The value that was expected. // info = Extra info to print out to make the error clearer. +// Example: +// assert_approx(3*9, 27, str("a=",3,", b=",9)); module assert_equal(got, expected, info) { no_children($children); if (got != expected || (is_nan(got) && is_nan(expected))) { @@ -536,9 +652,15 @@ module assert_equal(got, expected, info) { // shape_compare() {test_shape(); expected_shape();} // Description: // Compares two child shapes, returning empty geometry if they are very nearly the same shape and size. -// Returns the differential geometry if they are not nearly the same shape and size. +// Returns the differential geometry if they are not quite the same shape and size. // Arguments: // eps = The surface of the two shapes must be within this size of each other. Default: 1/1024 +// Example: +// $fn=36; +// shape_compare() { +// sphere(d=100); +// rotate_extrude() right_half(planar=true) circle(d=100); +// } module shape_compare(eps=1/1024) { union() { difference() { @@ -548,7 +670,7 @@ module shape_compare(eps=1/1024) { } else { minkowski() { children(1); - cube(eps, center=true); + spheroid(r=eps, style="octa"); } } } @@ -559,7 +681,7 @@ module shape_compare(eps=1/1024) { } else { minkowski() { children(0); - cube(eps, center=true); + spheroid(r=eps, style="octa"); } } } @@ -582,6 +704,7 @@ module shape_compare(eps=1/1024) { // to run the loop one extra time to return the final value. This tends to make the loop code // look rather ugly. The `looping()`, `loop_while()` and `loop_done()` functions // can make this somewhat more legible. +// . // ```openscad // function flat_sum(l) = [ // for ( @@ -604,11 +727,11 @@ module shape_compare(eps=1/1024) { // Function: looping() // Usage: -// looping(state) +// bool = looping(state); // Description: -// Returns true if the `state` value indicates the current loop should continue. -// This is useful when using C-style for loops to iteratively calculate a value. -// Used with `loop_while()` and `loop_done()`. See [Looping Helpers](#5-looping-helpers) for an example. +// Returns true if the `state` value indicates the current loop should continue. This is useful +// when using C-style for loops to iteratively calculate a value. Used with `loop_while()` and +// `loop_done()`. See [Looping Helpers](#5-looping-helpers) for an example. // Arguments: // state = The loop state value. function looping(state) = state < 2; @@ -616,12 +739,12 @@ function looping(state) = state < 2; // Function: loop_while() // Usage: -// state = loop_while(state, continue) +// state = loop_while(state, continue); // Description: // Given the current `state`, and a boolean `continue` that indicates if the loop should still be -// continuing, returns the updated state value for the the next loop. -// This is useful when using C-style for loops to iteratively calculate a value. -// Used with `looping()` and `loop_done()`. See [Looping Helpers](#5-looping-helpers) for an example. +// continuing, returns the updated state value for the the next loop. This is useful when using +// C-style for loops to iteratively calculate a value. Used with `looping()` and `loop_done()`. +// See [Looping Helpers](#5-looping-helpers) for an example. // Arguments: // state = The loop state value. // continue = A boolean value indicating whether the current loop should progress. @@ -632,11 +755,11 @@ function loop_while(state, continue) = // Function: loop_done() // Usage: -// loop_done(state) +// bool = loop_done(state); // Description: -// Returns true if the `state` value indicates the loop is finishing. -// This is useful when using C-style for loops to iteratively calculate a value. -// Used with `looping()` and `loop_while()`. See [Looping Helpers](#5-looping-helpers) for an example. +// Returns true if the `state` value indicates the loop is finishing. This is useful when using +// C-style for loops to iteratively calculate a value. Used with `looping()` and `loop_while()`. +// See [Looping Helpers](#5-looping-helpers) for an example. // Arguments: // state = The loop state value. function loop_done(state) = state > 0; diff --git a/rounding.scad b/rounding.scad index 83e4b28..39b4a42 100644 --- a/rounding.scad +++ b/rounding.scad @@ -223,7 +223,7 @@ function round_corners(path, method="circle", radius, cut, joint, k, closed=true assert(in_list(method,["circle", "smooth", "chamfer"]), "method must be one of \"circle\", \"smooth\" or \"chamfer\"") let( default_k = 0.5, - size=one_defined([radius, cut, joint], ["radius", "cut", "joint"]), + size=one_defined([radius, cut, joint], "radius,cut,joint"), path = is_region(path)? assert(len(path)==1, "Region supplied as path does not have exactly one component") path[0] : path, @@ -972,7 +972,7 @@ function offset_sweep( bottom_height = len(offsets_bot)==0 ? 0 : abs(select(offsets_bot,-1)[1]) - struct_val(bottom,"extra"), top_height = len(offsets_top)==0 ? 0 : abs(select(offsets_top,-1)[1]) - struct_val(top,"extra"), - height = get_height(l=l,h=h,height=height,dflt=bottom_height+top_height), + height = one_defined([l,h,height], "l,h,height", dflt=u_add(bottom_height,top_height)), middle = height-bottom_height-top_height ) echo(height=height) @@ -1241,7 +1241,7 @@ module convex_offset_extrude( bottom_height = len(offsets_bot)==0 ? 0 : abs(select(offsets_bot,-1)[1]) - struct_val(bottom,"extra"); top_height = len(offsets_top)==0 ? 0 : abs(select(offsets_top,-1)[1]) - struct_val(top,"extra"); - height = get_height(l=l,h=h,height=height,dflt=bottom_height+top_height); + height = one_defined([l,h,height], "l,h,height", dflt=u_add(bottom_height,top_height)); assert(height>=0, "Height must be nonnegative"); middle = height-bottom_height-top_height; @@ -1809,7 +1809,7 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b k_top = default(k_top, k), k_bot = default(k_bot, k), k_sides = default(k_sides, k), - height = one_defined([h,l,height,length],["height","length","l","h"], required=false), + height = one_defined([h,l,height,length],"height,length,l,h", dflt=undef), shapedimok = (len(bottom[0])==3 && is_path(top,3)) || (len(bottom[0])==2 && (is_undef(top) || is_path(top,2))) ) assert(is_num(k_top) && k_top>=0 && k_top<=1, "Curvature parameter k_top must be in interval [0,1]") diff --git a/tests/test_common.scad b/tests/test_common.scad index d51acea..268640a 100644 --- a/tests/test_common.scad +++ b/tests/test_common.scad @@ -276,10 +276,10 @@ test_first_defined(); module test_one_defined() { - assert_equal(one_defined([27,undef,undef], ["length","L","l"]) ,27); - assert_equal(one_defined([undef,28,undef], ["length","L","l"]) ,28); - assert_equal(one_defined([undef,undef,29], ["length","L","l"]) ,29); - assert_equal(one_defined([undef,undef,undef], ["length","L","l"], required=false), undef); + assert_equal(one_defined([27,undef,undef], "length,L,l"]) ,27); + assert_equal(one_defined([undef,28,undef], "length,L,l"]) ,28); + assert_equal(one_defined([undef,undef,29], "length,L,l"]) ,29); + assert_equal(one_defined([undef,undef,undef], "length,L,l"], dflt=undef), undef); } test_one_defined(); @@ -361,19 +361,6 @@ module test_get_radius() { test_get_radius(); -module test_get_height() { - assert(get_height(h=undef, l=undef, height=undef, dflt=undef) == undef); - assert(get_height(h=undef, l=undef, height=undef, dflt=23) == 23); - assert(get_height(h=undef, l=undef, height=50, dflt=23) == 50); - assert(get_height(h=undef, l=50, height=undef, dflt=23) == 50); - assert(get_height(h=50, l=undef, height=undef, dflt=23) == 50); - assert(get_height(h=undef, l=undef, height=75, dflt=23) == 75); - assert(get_height(h=undef, l=75, height=undef, dflt=23) == 75); - assert(get_height(h=75, l=undef, height=undef, dflt=23) == 75); -} -test_get_height(); - - module test_scalar_vec3() { assert(scalar_vec3(undef) == undef); assert(scalar_vec3(3) == [3,3,3]); diff --git a/version.scad b/version.scad index 853d099..9a023d8 100644 --- a/version.scad +++ b/version.scad @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,544]; +BOSL_VERSION = [2,0,545]; // Section: BOSL Library Version Functions