1//////////////////////////////////////////////////////////////////////
   2// LibFile: utility.scad
   3//   Functions for type checking, handling undefs, processing function arguments,
   4//   and testing. 
   5// Includes:
   6//   include <BOSL2/std.scad>
   7// FileGroup: Data Management
   8// FileSummary: Type checking, dealing with undefs, processing function args
   9// FileFootnotes: STD=Included in std.scad
  10//////////////////////////////////////////////////////////////////////
  11
  12
  13
  14// Section: Type Checking
  15
  16
  17// Function: typeof()
  18// Synopsis: Returns a string representing the type of the value.
  19// Topics: Type Checking
  20// See Also: is_type()
  21// Usage:
  22//   typ = typeof(x);
  23// Description:
  24//   Returns a string representing the type of the value.  One of "undef", "boolean", "number", "nan", "string", "list", "range", "function" or "invalid".
  25//   Some malformed "ranges", like '[0:NAN:INF]' and '[0:"a":INF]', may be classified as "undef" or "invalid".
  26// Arguments:
  27//   x = value whose type to check
  28// Example:
  29//   typ = typeof(undef);  // Returns: "undef"
  30//   typ = typeof(true);  // Returns: "boolean"
  31//   typ = typeof(42);  // Returns: "number"
  32//   typ = typeof(NAN);  // Returns: "nan"
  33//   typ = typeof("foo");  // Returns: "string"
  34//   typ = typeof([3,4,5]);  // Returns: "list"
  35//   typ = typeof([3:1:8]);  // Returns: "range"
  36//   typ = typeof(function (x,y) x+y);  // Returns: "function"
  37function typeof(x) =
  38    is_undef(x)? "undef" :
  39    is_bool(x)? "boolean" :
  40    is_num(x)? "number" :
  41    is_nan(x)? "nan" :
  42    is_string(x)? "string" :
  43    is_list(x)? "list" :
  44    is_range(x) ? "range" :
  45    version_num()>20210000 && is_function(x) ? "function" :
  46    "invalid";
  47
  48
  49// Function: is_type()
  50// Synopsis: Returns true if the type of 'x' is one of those in the list `types`.
  51// Topics: Type Checking
  52// See Also: typeof()
  53// Usage:
  54//   bool = is_type(x, types);
  55// Description:
  56//   Returns true if the type of the value `x` is one of those given as strings in the list `types`. 
  57//   Valid types are "undef", "boolean", "number", "nan", "string", "list", "range", or "function".
  58// Arguments:
  59//   x = The value to check the type of.
  60//   types = A list of types to check 
  61// Example:
  62//   is_str_or_list = is_type("foo", ["string","list"]);   // Returns: true
  63//   is_str_or_list2 = is_type([1,2,3], ["string","list"]);  // Returns: true
  64//   is_str_or_list3 = is_type(2, ["string","list"]);  // Returns: false
  65//   is_str = is_type("foo", "string");  // Returns: true
  66//   is_str2 = is_type([3,4], "string");  // Returns: false
  67//   is_str3 = is_type(["foo"], "string");  // Returns: false
  68//   is_str4 = is_type(3, "string");  // Returns: false
  69function is_type(x,types) =
  70    is_list(types)? in_list(typeof(x),types) :
  71    is_string(types)? typeof(x) == types :
  72    assert(is_list(types)||is_string(types));
  73
  74
  75// Function: is_def()
  76// Synopsis: Returns true if `x` is not `undef`.
  77// Topics: Type Checking
  78// See Also: typeof(), is_type(), is_str()
  79// Usage:
  80//   bool = is_def(x);
  81// Description:
  82//   Returns true if `x` is not `undef`.  False if `x==undef`.
  83// Arguments:
  84//   x = value to check
  85// Example:
  86//   bool = is_def(undef);  // Returns: false
  87//   bool = is_def(false);  // Returns: true
  88//   bool = is_def(42);     // Returns: true
  89//   bool = is_def("foo");  // Returns: true
  90function is_def(x) = !is_undef(x);
  91
  92
  93// Function: is_str()
  94// Synopsis: Returns true if the argument is a string.
  95// Topics: Type Checking
  96// See Also: typeof(), is_type(), is_int(), is_def(), is_int()
  97// Usage:
  98//   bool = is_str(x);
  99// Description:
 100//   Returns true if `x` is a string.  A shortcut for `is_string()`.
 101// Arguments:
 102//   x = value to check
 103// Example:
 104//   bool = is_str(undef);  // Returns: false
 105//   bool = is_str(false);  // Returns: false
 106//   bool = is_str(42);     // Returns: false
 107//   bool = is_str("foo");  // Returns: true
 108function is_str(x) = is_string(x);
 109
 110
 111// Function: is_int()
 112// Alias: is_integer()
 113// Synopsis: Returns true if the argument is an integer.
 114// Topics: Type Checking
 115// See Also: typeof(), is_type(), is_str(), is_def()
 116// Usage:
 117//   bool = is_int(n);
 118//   bool = is_integer(n);
 119// Description:
 120//   Returns true if the given value is an integer (it is a number and it rounds to itself).  
 121// Arguments:
 122//   n = value to check
 123// Example:
 124//   bool = is_int(undef);  // Returns: false
 125//   bool = is_int(false);  // Returns: false
 126//   bool = is_int(42);     // Returns: true
 127//   bool = is_int("foo");  // Returns: false
 128function is_int(n) = is_finite(n) && n == round(n);
 129function is_integer(n) = is_finite(n) && n == round(n);
 130
 131
 132// Function: all_integer()
 133// Synopsis: Returns true if all of the numbers in the argument are integers.
 134// Topics: Type Checking
 135// See also: is_int(), typeof(), is_type()
 136// Usage:
 137//   bool = all_integer(x);
 138// Description:
 139//   If given a number, returns true if the number is a finite integer.
 140//   If given an empty list, returns false.  If given a non-empty list, returns
 141//   true if every item of the list is an integer.  Otherwise, returns false.
 142// Arguments:
 143//   x = The value to check.
 144// Example:
 145//   b = all_integer(true);  // Returns: false
 146//   b = all_integer("foo"); // Returns: false
 147//   b = all_integer(4);     // Returns: true
 148//   b = all_integer(4.5);   // Returns: false
 149//   b = all_integer([]);    // Returns: false
 150//   b = all_integer([3,4,5]);   // Returns: true
 151//   b = all_integer([3,4.2,5]); // Returns: false
 152//   b = all_integer([3,[4,7],5]); // Returns: false
 153function all_integer(x) =
 154    is_num(x)? is_int(x) :
 155    is_list(x)? (x != [] && [for (xx=x) if(!is_int(xx)) 1] == []) :
 156    false;
 157
 158
 159// Function: is_nan()
 160// Synopsis: Return true if the argument is "not a number".
 161// Topics: Type Checking
 162// See Also: typeof(), is_type(), is_str(), is_def(), is_int(), is_finite()
 163// Usage:
 164//   bool = is_nan(x);
 165// Description:
 166//   Returns true if a given value `x` is nan, a floating point value representing "not a number".
 167// Arguments:
 168//   x = value to check
 169// Example:
 170//   bool = is_nan(undef);  // Returns: false
 171//   bool = is_nan(false);  // Returns: false
 172//   bool = is_nan(42);     // Returns: false
 173//   bool = is_nan("foo");  // Returns: false
 174//   bool = is_nan(NAN);    // Returns: true
 175function is_nan(x) = (x!=x);
 176
 177
 178// Function: is_finite()
 179// Synopsis: Returns true if the argument is a finite number.
 180// Topics: Type Checking
 181// See Also: typeof(), is_type(), is_str(), is_def(), is_int(), is_nan()
 182// Usage:
 183//   bool = is_finite(x);
 184// Description:
 185//   Returns true if a given value `x` is a finite number.
 186// Arguments:
 187//   x = value to check
 188// Example:
 189//   bool = is_finite(undef);  // Returns: false
 190//   bool = is_finite(false);  // Returns: false
 191//   bool = is_finite(42);     // Returns: true
 192//   bool = is_finite("foo");  // Returns: false
 193//   bool = is_finite(NAN);    // Returns: false
 194//   bool = is_finite(INF);    // Returns: false
 195//   bool = is_finite(-INF);   // Returns: false
 196function is_finite(x) = is_num(x) && !is_nan(0*x);
 197
 198
 199// Function: is_range()
 200// Synopsis: Returns true if the argument is a range.
 201// Topics: Type Checking
 202// See Also: typeof(), is_type(), is_str(), is_def(), is_int()
 203// Usage:
 204//   bool = is_range(x);
 205// Description:
 206//   Returns true if its argument is a range
 207// Arguments:
 208//   x = value to check
 209// Example:
 210//   bool = is_range(undef);   // Returns: false
 211//   bool = is_range(false);   // Returns: false
 212//   bool = is_range(42);      // Returns: false
 213//   bool = is_range([3,4,5]); // Returns: false
 214//   bool = is_range("foo");   // Returns: false
 215//   bool = is_range([3:5]);   // Returns: true
 216function is_range(x) = !is_list(x) && is_finite(x[0]) && is_finite(x[1]) && is_finite(x[2]) ;
 217
 218
 219// Function: valid_range()
 220// Synopsis: Returns true if the argument is a valid range.
 221// Topics: Type Checking
 222// See Also: typeof(), is_type(), is_str(), is_def(), is_int(), is_range()
 223// Usage:
 224//   bool = valid_range(x);
 225// Description:
 226//   Returns true if its argument is a valid range (deprecated ranges excluded).
 227// Arguments:
 228//   x = value to check
 229// Example:
 230//   bool = is_range(undef);   // Returns: false
 231//   bool = is_range(false);   // Returns: false
 232//   bool = is_range(42);      // Returns: false
 233//   bool = is_range([3,4,5]); // Returns: false
 234//   bool = is_range("foo");   // Returns: false
 235//   bool = is_range([3:5]);   // Returns: true
 236//   bool = is_range([3:1]);   // Returns: false
 237function valid_range(x) = 
 238    is_range(x) 
 239    && ( x[1]>0 
 240         ? x[0]<=x[2]
 241         : ( x[1]<0 && x[0]>=x[2] ) );
 242
 243
 244// Function: is_func()
 245// Synopsis: Returns true if the argument is a function literal.
 246// Topics: Type Checking, Function Literals
 247// See also: is_type(), typeof()
 248// Usage:
 249//   bool = is_func(x);
 250// Description:
 251//   Returns true if OpenSCAD supports function literals, and the given item is one.
 252// Arguments:
 253//   x = The value to check
 254// Example:
 255//   f = function (a) a==2;
 256//   bool = is_func(f);  // Returns: true
 257function is_func(x) = version_num()>20210000 && is_function(x);
 258
 259
 260// Function: is_consistent()
 261// Synopsis: Returns true if the argument is a list with consistent structure and finite numerical data.
 262// Topics: Type Checking, Testing
 263// See Also: typeof(), is_type(), is_str(), is_def(), is_int(), is_range(), is_homogeneous()
 264// Usage:
 265//   bool = is_consistent(list, [pattern]);
 266// Description:
 267//   Tests whether input is a list of entries which all have the same list structure
 268//   and are filled with finite numerical data.  You can optionally specify a required 
 269//   list structure with the pattern argument.  
 270//   It returns `true` for the empty list regardless the value of the `pattern`.
 271// Arguments:
 272//   list = list to check
 273//   pattern = optional pattern required to match
 274// Example:
 275//   is_consistent([3,4,5]);              // Returns true
 276//   is_consistent([[3,4],[4,5],[6,7]]);  // Returns true
 277//   is_consistent([[3,4,5],[3,4]]);      // Returns false
 278//   is_consistent([[3,[3,4,[5]]], [5,[2,9,[9]]]]); // Returns true
 279//   is_consistent([[3,[3,4,[5]]], [5,[2,9,9]]]);   // Returns false
 280//   is_consistent([3,4,5], 0);            // Returns true
 281//   is_consistent([3,4,undef], 0);        // Returns false
 282//   is_consistent([[3,4],[4,5]], [1,1]);  // Returns true
 283//   is_consistent([[3,"a"],[4,true]], [1,undef]);  // Returns true
 284//   is_consistent([[3,4], 6, [4,5]], [1,1]);  // Returns false
 285//   is_consistent([[1,[3,4]], [4,[5,6]]], [1,[2,3]]);    // Returns true
 286//   is_consistent([[1,[3,INF]], [4,[5,6]]], [1,[2,3]]);  // Returns false
 287//   is_consistent([], [1,[2,3]]);                        // Returns true
 288function is_consistent(list, pattern) =
 289    is_list(list) 
 290    && (len(list)==0 
 291       || (let(pattern = is_undef(pattern) ? _list_pattern(list[0]): _list_pattern(pattern) )
 292          []==[for(entry=0*list) if (entry != pattern) entry]));
 293
 294//Internal function
 295//Creates a list with the same structure of `list` with each of its elements replaced by 0.
 296function _list_pattern(list) =
 297  is_list(list) 
 298  ? [for(entry=list) is_list(entry) ? _list_pattern(entry) : 0]
 299  : 0;
 300
 301
 302// Function: same_shape()
 303// Synopsis: Returns true if the argument lists are numeric and of the same shape.
 304// Topics: Type Checking, Testing
 305// See Also: is_homogeneous(), is_consistent()
 306// Usage:
 307//   bool = same_shape(a,b);
 308// Description:
 309//   Tests whether the inputs `a` and `b` are both numeric and are the same shaped list.
 310// Example:
 311//   same_shape([3,[4,5]],[7,[3,4]]);   // Returns true
 312//   same_shape([3,4,5], [7,[3,4]]);    // Returns false
 313function same_shape(a,b) = is_def(b) && _list_pattern(a) == b*0;
 314
 315
 316// Function: is_bool_list()
 317// Synopsis: Returns true if the argument list contains only booleans.
 318// Topics: Boolean Testing
 319// See Also: is_homogeneous(), is_consistent()
 320// Usage:
 321//   check = is_bool_list(list,[length])
 322// Description:
 323//   Tests whether input is a list containing only booleans, and optionally checks its length.
 324// Arguments:
 325//   list = list to test
 326//   length = if given, list must be this length
 327function is_bool_list(list, length) =
 328     is_list(list) && (is_undef(length) || len(list)==length) && []==[for(entry=list) if (!is_bool(entry)) 1];
 329
 330
 331// Section: Boolean list testing
 332
 333// Function: any()
 334// Synopsis: Returns true if any item in the argument list is true.
 335// Topics: Type Checking
 336// See Also: all(), num_true()
 337// Usage:
 338//   bool = any(l);
 339//   bool = any(l, func);   // Requires OpenSCAD 2021.01 or later.
 340// Requirements:
 341//   Requires OpenSCAD 2021.01 or later to use the `func` argument.
 342// Description:
 343//   Returns true if any item in list `l` evaluates as true.
 344//   If `func` is given then returns true if the function evaluates as true on any list entry. 
 345//   Items that evaluate as true include nonempty lists, nonempty strings, and nonzero numbers.
 346// Arguments:
 347//   l = The list to test for true items.
 348//   func = An optional function literal of signature (x), returning bool, to test each list item with.
 349// Example:
 350//   any([0,false,undef]);  // Returns false.
 351//   any([1,false,undef]);  // Returns true.
 352//   any([1,5,true]);       // Returns true.
 353//   any([[0,0], [0,0]]);   // Returns true.
 354//   any([[0,0], [1,0]]);   // Returns true.
 355function any(l, func) =
 356    assert(is_list(l), "The input is not a list." )
 357    assert(func==undef || is_func(func))
 358    is_func(func)
 359      ? _any_func(l, func)
 360      : _any_bool(l);
 361
 362function _any_func(l, func, i=0, out=false) =
 363    i >= len(l) || out? out :
 364    _any_func(l, func, i=i+1, out=out || func(l[i]));
 365
 366function _any_bool(l, i=0, out=false) =
 367    i >= len(l) || out? out :
 368    _any_bool(l, i=i+1, out=out || l[i]);
 369
 370
 371// Function: all()
 372// Synopsis: Returns true if all items in the argument list are true.
 373// Topics: Type Checking
 374// See Also: any(), num_true()
 375// Usage:
 376//   bool = all(l);
 377//   bool = all(l, func);   // Requires OpenSCAD 2021.01 or later.
 378// Requirements:
 379//   Requires OpenSCAD 2021.01 or later to use the `func` argument.
 380// Description:
 381//   Returns true if all items in list `l` evaluate as true.
 382//   If `func` is given then returns true if the function evaluates as true on all list etnries. 
 383//   Items that evaluate as true include nonempty lists, nonempty strings, and nonzero numbers.
 384// Arguments:
 385//   l = The list to test for true items.
 386//   func = An optional function literal of signature (x), returning bool, to test each list item with.
 387// Example:
 388//   test1 = all([0,false,undef]);  // Returns false.
 389//   test2 = all([1,false,undef]);  // Returns false.
 390//   test3 = all([1,5,true]);       // Returns true.
 391//   test4 = all([[0,0], [0,0]]);   // Returns true.
 392//   test5 = all([[0,0], [1,0]]);   // Returns true.
 393//   test6 = all([[1,1], [1,1]]);   // Returns true.
 394function all(l, func) =
 395    assert(is_list(l), "The input is not a list.")
 396    assert(func==undef || is_func(func))
 397    is_func(func)
 398      ? _all_func(l, func)
 399      : _all_bool(l);
 400
 401function _all_func(l, func, i=0, out=true) =
 402    i >= len(l) || !out? out :
 403    _all_func(l, func, i=i+1, out=out && func(l[i]));
 404
 405function _all_bool(l, i=0, out=true) =
 406    i >= len(l) || !out? out :
 407    _all_bool(l, i=i+1, out=out && l[i]);
 408
 409
 410// Function: num_true()
 411// Synopsis: Returns the number of true entries in the arguemnt list.
 412// Topics: Boolean Testing
 413// See Also: any(), all()
 414// Usage:
 415//   seq = num_true(l);
 416//   seq = num_true(l, func);  // Requires OpenSCAD 2021.01 or later.
 417// Requirements:
 418//   Requires OpenSCAD 2021.01 or later to use the `func=` argument.
 419// Description:
 420//   Returns the number of items in `l` that evaluate as true.  If `func` is given then counts
 421//   list entries where the function evaluates as true.  
 422//   Items that evaluate as true include nonempty lists, nonempty strings, and nonzero numbers.
 423// Arguments:
 424//   l = The list to test for true items.
 425//   func = An optional function literal of signature (x), returning bool, to test each list item with.
 426// Example:
 427//   num1 = num_true([0,false,undef]);  // Returns 0.
 428//   num2 = num_true([1,false,undef]);  // Returns 1.
 429//   num3 = num_true([1,5,false]);      // Returns 2.
 430//   num4 = num_true([1,5,true]);       // Returns 3.
 431//   num5 = num_true([[0,0], [0,0]]);   // Returns 2.
 432//   num6 = num_true([[], [1,0]]);      // Returns 1.
 433function num_true(l, func) = 
 434    assert(is_list(l))
 435    assert(func==undef || is_func(func))
 436    let(
 437        true_list = is_def(func)? [for(entry=l) if (func(entry)) 1]
 438                                : [for(entry=l) if (entry) 1]
 439    )
 440    len(true_list);
 441
 442
 443
 444// Section: Handling `undef`s.
 445
 446
 447// Function: default()
 448// Synopsis: Returns a default value if the argument is 'undef', else returns the argument.
 449// Topics: Undef Handling
 450// See Also: first_defined(), one_defined(), num_defined()
 451// Usage:
 452//   val = default(val, dflt);
 453// Description:
 454//   Returns the value given as `v` if it is not `undef`.
 455//   Otherwise, returns the value of `dflt`.
 456// Arguments:
 457//   v = Value to pass through if not `undef`.
 458//   dflt = Value to return if `v` *is* `undef`.  Default: undef
 459function default(v,dflt=undef) = is_undef(v)? dflt : v;
 460
 461
 462// Function: first_defined()
 463// Synopsis: Returns the first value in the argument list that is not 'undef'.
 464// Topics: Undef Handling
 465// See Also: default(), one_defined(), num_defined(), any_defined(), all_defined()
 466// Usage:
 467//   val = first_defined(v, [recursive]);
 468// Description:
 469//   Returns the first item in the list that is not `undef`.
 470//   If all items are `undef`, or list is empty, returns `undef`.
 471// Arguments:
 472//   v = The list whose items are being checked.
 473//   recursive = If true, sublists are checked recursively for defined values.  The first sublist that has a defined item is returned.  Default: false
 474// Example:
 475//   val = first_defined([undef,7,undef,true]);  // Returns: 7
 476function first_defined(v,recursive=false,_i=0) =
 477    _i<len(v) && (
 478        is_undef(v[_i]) || (
 479            recursive &&
 480            is_list(v[_i]) &&
 481            is_undef(first_defined(v[_i],recursive=recursive))
 482        )
 483    )? first_defined(v,recursive=recursive,_i=_i+1) : v[_i];
 484    
 485
 486// Function: one_defined()
 487// Synopsis: Returns the defined value in the argument list if only a single value is defined.
 488// Topics: Undef Handling
 489// See Also: default(), first_defined(), num_defined(), any_defined(), all_defined()
 490// Usage:
 491//   val = one_defined(vals, names, [dflt])
 492// Description:
 493//   Examines the input list `vals` and returns the entry which is not `undef`.
 494//   If more than one entry is not `undef` then an error is asserted, specifying
 495//   "Must define exactly one of" followed by the names in the `names` parameter.
 496//   If `dflt` is given, and all `vals` are `undef`, then the value in `dflt` is returned.
 497//   If `dflt` is *not* given, and all `vals` are `undef`, then an error is asserted.
 498// Arguments:
 499//   vals = The values to return the first one which is not `undef`.
 500//   names = A string with comma-separated names for the arguments whose values are passed in `vals`.
 501//   dflt = If given, the value returned if all `vals` are `undef`.
 502// Example:
 503//   length1 = one_defined([length,L,l], ["length","L","l"]);
 504//   length2 = one_defined([length,L,l], "length,L,l", dflt=1);
 505
 506function one_defined(vals, names, dflt=_UNDEF) = 
 507    let(
 508        checkargs = is_list(names)? assert(len(vals) == len(names)) :
 509            is_string(names)? let(
 510                name_cnt = len([for (c=names) if (c==",") 1]) + 1
 511            ) assert(len(vals) == name_cnt) :
 512            assert(is_list(names) || is_string(names)) 0,
 513        ok = num_defined(vals)==1 || (dflt!=_UNDEF && num_defined(vals)==0)
 514    ) ok? default(first_defined(vals), dflt) :
 515    let(
 516        names = is_string(names) ? str_split(names,",") : names,
 517        defd = [for (i=idx(vals)) if (is_def(vals[i])) names[i]],
 518        msg = str(
 519            "Must define ",
 520            dflt==_UNDEF? "exactly" : "at most",
 521            " one of ",
 522            num_defined(vals) == 0 ? names : defd
 523        )
 524    ) assert(ok,msg);
 525
 526
 527// Function: num_defined()
 528// Synopsis: Returns the number of defined values in the the argument list.
 529// Topics: Undef Handling
 530// See Also: default(), first_defined(), one_defined(), any_defined(), all_defined()
 531// Usage:
 532//   cnt = num_defined(v);
 533// Description:
 534//   Counts how many items in list `v` are not `undef`.
 535// Example:
 536//   cnt = num_defined([3,7,undef,2,undef,undef,1]);  // Returns: 4
 537function num_defined(v) =
 538    len([for(vi=v) if(!is_undef(vi)) 1]);
 539
 540
 541// Function: any_defined()
 542// Synopsis: Returns true if any item in the argument list is not `undef`.
 543// Topics: Undef Handling
 544// See Also: default(), first_defined(), one_defined(), num_defined(), all_defined()
 545// Usage:
 546//   bool = any_defined(v, [recursive]);
 547// Description:
 548//   Returns true if any item in the given array is not `undef`.
 549// Arguments:
 550//   v = The list whose items are being checked.
 551//   recursive = If true, any sublists are evaluated recursively.  Default: false
 552// Example:
 553//   bool = any_defined([undef,undef,undef]);    // Returns: false
 554//   bool = any_defined([undef,42,undef]);       // Returns: true
 555//   bool = any_defined([34,42,87]);             // Returns: true
 556//   bool = any_defined([undef,undef,[undef]]);  // Returns: true
 557//   bool = any_defined([undef,undef,[undef]],recursive=true);  // Returns: false
 558//   bool = any_defined([undef,undef,[42]],recursive=true);     // Returns: true
 559function any_defined(v,recursive=false) =
 560    first_defined(v,recursive=recursive) != undef;
 561
 562
 563// Function: all_defined()
 564// Synopsis: Returns true if all items in the given array are defined.
 565// Topics: Undef Handling
 566// See Also: default(), first_defined(), one_defined(), num_defined(), all_defined()
 567// Usage:
 568//   bool = all_defined(v, [recursive]);
 569// Description:
 570//   Returns true if all items in the given array are not `undef`.
 571// Arguments:
 572//   v = The list whose items are being checked.
 573//   recursive = If true, any sublists are evaluated recursively.  Default: false
 574// Example:
 575//   bool = all_defined([undef,undef,undef]);    // Returns: false
 576//   bool = all_defined([undef,42,undef]);       // Returns: false
 577//   bool = all_defined([34,42,87]);             // Returns: true
 578//   bool = all_defined([23,34,[undef]]);        // Returns: true
 579//   bool = all_defined([23,34,[undef]],recursive=true);  // Returns: false
 580//   bool = all_defined([23,34,[42]],recursive=true);     // Returns: true
 581function all_defined(v,recursive=false) = 
 582    []==[for (x=v) if(is_undef(x)||(recursive && is_list(x) && !all_defined(x,recursive))) 0 ];
 583
 584
 585
 586// Section: Undef Safe Arithmetic
 587
 588// Function: u_add()
 589// Synopsis: Returns the sum of 2 numbers if both are defined, otherwise returns undef.
 590// Topics: Undef Handling
 591// See Also: u_sub(), u_mul(), u_div()
 592// Usage:
 593//   x = u_add(a, b);
 594// Description:
 595//   Adds `a` to `b`, returning the result, or undef if either value is `undef`.
 596//   This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
 597// Arguments:
 598//   a = First value.
 599//   b = Second value.
 600function u_add(a,b) = is_undef(a) || is_undef(b)? undef : a + b;
 601
 602
 603// Function: u_sub()
 604// Synopsis: Returns the difference of 2 numbers if both are defined, otherwise returns undef.
 605// Topics: Undef Handling
 606// See Also: u_add(), u_mul(), u_div()
 607// Usage:
 608//   x = u_sub(a, b);
 609// Description:
 610//   Subtracts `b` from `a`, returning the result, or undef if either value is `undef`.
 611//   This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
 612// Arguments:
 613//   a = First value.
 614//   b = Second value.
 615function u_sub(a,b) = is_undef(a) || is_undef(b)? undef : a - b;
 616
 617
 618// Function: u_mul()
 619// Synopsis: Returns the product of 2 numbers if both are defined, otherwise returns undef.
 620// Topics: Undef Handling
 621// See Also: u_add(), u_sub(), u_div()
 622// Usage:
 623//   x = u_mul(a, b);
 624// Description:
 625//   Multiplies `a` by `b`, returning the result, or undef if either value is `undef`.
 626//   This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
 627// Arguments:
 628//   a = First value.
 629//   b = Second value.
 630function u_mul(a,b) =
 631    is_undef(a) || is_undef(b)? undef :
 632    is_vector(a) && is_vector(b)? v_mul(a,b) :
 633    a * b;
 634
 635
 636// Function: u_div()
 637// Synopsis: Returns the quotient of 2 numbers if both are defined, otherwise returns undef.
 638// Topics: Undef Handling
 639// See Also: u_add(), u_sub(), u_mul()
 640// Usage:
 641//   x = u_div(a, b);
 642// Description:
 643//   Divides `a` by `b`, returning the result, or undef if either value is `undef`.
 644//   This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
 645// Arguments:
 646//   a = First value.
 647//   b = Second value.
 648function u_div(a,b) =
 649    is_undef(a) || is_undef(b)? undef :
 650    is_vector(a) && is_vector(b)? v_div(a,b) :
 651    a / b;
 652
 653
 654
 655
 656// Section: Processing Arguments to Functions and Modules
 657
 658
 659// Function: get_anchor()
 660// Synopsis: Returns the correct anchor from `anchor` and `center`.
 661// Topics: Argument Handling
 662// See Also: get_radius()
 663// Usage:
 664//   anchr = get_anchor(anchor,center,[uncentered],[dflt]);
 665// Description:
 666//   Calculated the correct anchor from `anchor` and `center`.  In order:
 667//   - If `center` is not `undef` and `center` evaluates as true, then `CENTER` (`[0,0,0]`) is returned.
 668//   - Otherwise, if `center` is not `undef` and `center` evaluates as false, then the value of `uncentered` is returned.
 669//   - Otherwise, if `anchor` is not `undef`, then the value of `anchor` is returned.
 670//   - Otherwise, the value of `dflt` is returned.
 671//   This ordering ensures that `center` will override `anchor`.
 672// Arguments:
 673//   anchor = The anchor name or vector.
 674//   center = If not `undef`, this overrides the value of `anchor`.
 675//   uncentered = The value to return if `center` is not `undef` and evaluates as false.  Default: BOTTOM
 676//   dflt = The default value to return if both `anchor` and `center` are `undef`.  Default: `CENTER`
 677// Example:
 678//   anchr1 = get_anchor(undef, undef, BOTTOM, TOP);  // Returns: [0, 0, 1] (TOP)
 679//   anchr2 = get_anchor(RIGHT, undef, BOTTOM, TOP);  // Returns: [1, 0, 0] (RIGHT)
 680//   anchr3 = get_anchor(undef, false, BOTTOM, TOP);  // Returns: [0, 0,-1] (BOTTOM)
 681//   anchr4 = get_anchor(RIGHT, false, BOTTOM, TOP);  // Returns: [0, 0,-1] (BOTTOM)
 682//   anchr5 = get_anchor(undef, true,  BOTTOM, TOP);  // Returns: [0, 0, 0] (CENTER)
 683//   anchr6 = get_anchor(RIGHT, true,  BOTTOM, TOP);  // Returns: [0, 0, 0] (CENTER)
 684function get_anchor(anchor,center,uncentered=BOT,dflt=CENTER) =
 685    !is_undef(center)? (center? CENTER : uncentered) :
 686    !is_undef(anchor)? anchor :
 687    dflt;
 688
 689
 690// Function: get_radius()
 691// Synopsis: Given various radii and diameters, returns the most specific radius.
 692// Topics: Argument Handling
 693// See Also: get_anchor()
 694// Usage:
 695//   r = get_radius([r1=], [r2=], [r=], [d1=], [d2=], [d=], [dflt=]);
 696// Description:
 697//   Given various radii and diameters, returns the most specific radius.  If a diameter is most
 698//   specific, returns half its value, giving the radius.  If no radii or diameters are defined,
 699//   returns the value of `dflt`.  Value specificity order is `r1`, `r2`, `d1`, `d2`, `r`, `d`,
 700//   then `dflt`.  Only one of `r1`, `r2`, `d1`, or `d2` can be defined at once, or else it errors
 701//   out, complaining about conflicting radius/diameter values.  
 702// Arguments:
 703//   ---
 704//   r1 = Most specific radius.
 705//   r2 = Second most specific radius.
 706//   r = Most general radius.
 707//   d1 = Most specific diameter.
 708//   d2 = Second most specific diameter.
 709//   d = Most general diameter.
 710//   dflt = Value to return if all other values given are `undef`.
 711// Example:
 712//   r = get_radius(r1=undef, r=undef, dflt=undef);  // Returns: undef
 713//   r = get_radius(r1=undef, r=undef, dflt=1);      // Returns: 1
 714//   r = get_radius(r1=undef, r=6, dflt=1);          // Returns: 6
 715//   r = get_radius(r1=7, r=6, dflt=1);              // Returns: 7
 716//   r = get_radius(r1=undef, r2=8, r=6, dflt=1);    // Returns: 8
 717//   r = get_radius(r1=undef, r2=8, d=6, dflt=1);    // Returns: 8
 718//   r = get_radius(r1=undef, d=6, dflt=1);          // Returns: 3
 719//   r = get_radius(d1=7, d=6, dflt=1);              // Returns: 3.5
 720//   r = get_radius(d1=7, d2=8, d=6, dflt=1);        // Returns: 3.5
 721//   r = get_radius(d1=undef, d2=8, d=6, dflt=1);    // Returns: 4
 722//   r = get_radius(r1=8, d=6, dflt=1);              // Returns: 8
 723function get_radius(r1, r2, r, d1, d2, d, dflt) = 
 724    assert(num_defined([r1,d1,r2,d2])<2, "Conflicting or redundant radius/diameter arguments given.")
 725    assert(num_defined([r,d])<2, "Conflicting or redundant radius/diameter arguments given.")
 726    let(
 727        rad = !is_undef(r1) ?  r1 
 728            : !is_undef(d1) ?  d1/2
 729            : !is_undef(r2) ?  r2
 730            : !is_undef(d2) ?  d2/2
 731            : !is_undef(r)  ?  r
 732            : !is_undef(d)  ?  d/2
 733            : dflt
 734    )
 735    assert(is_undef(dflt) || is_finite(rad) || is_vector(rad), "Invalid radius." )
 736    rad;
 737
 738
 739// Function: scalar_vec3()
 740// Synopsis: Expands a scalar or a list with length less than 3 to a length 3 vector. 
 741// Topics: Argument Handling
 742// See Also: get_anchor(), get_radius(), force_list()
 743// Usage:
 744//   vec = scalar_vec3(v, [dflt]);
 745// Description:
 746//   This is expands a scalar or a list with length less than 3 to a length 3 vector in the
 747//   same way that OpenSCAD expands short vectors in some contexts, e.g. cube(10) or rotate([45,90]).  
 748//   If `v` is a scalar, and `dflt==undef`, returns `[v, v, v]`.
 749//   If `v` is a scalar, and `dflt!=undef`, returns `[v, dflt, dflt]`.
 750//   If `v` is a vector and dflt is defined, returns the first 3 items, with any missing values replaced by `dflt`.
 751//   If `v` is a vector and dflt is undef, returns the first 3 items, with any missing values replaced by 0.
 752//   If `v` is `undef`, returns `undef`.
 753// Arguments:
 754//   v = Value to return vector from.
 755//   dflt = Default value to set empty vector parts from.
 756// Example:
 757//   vec = scalar_vec3(undef);      // Returns: undef
 758//   vec = scalar_vec3(10);         // Returns: [10,10,10]
 759//   vec = scalar_vec3(10,1);       // Returns: [10,1,1]
 760//   vec = scalar_vec3([10,10],1);  // Returns: [10,10,1]
 761//   vec = scalar_vec3([10,10]);    // Returns: [10,10,0]
 762//   vec = scalar_vec3([10]);       // Returns: [10,0,0]
 763function scalar_vec3(v, dflt) =
 764    is_undef(v)? undef :
 765    is_list(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] :
 766    !is_undef(dflt)? [v,dflt,dflt] : [v,v,v];
 767
 768
 769// Function: segs()
 770// Synopsis: Returns the number of sides for a circle given `$fn`, `$fa`, and `$fs`.
 771// Topics: Geometry
 772// See Also: circle(), cyl()
 773// Usage:
 774//   sides = segs(r);
 775// Description:
 776//   Calculate the standard number of sides OpenSCAD would give a circle based on `$fn`, `$fa`, and `$fs`.
 777// Arguments:
 778//   r = Radius of circle to get the number of segments for.
 779// Example:
 780//   $fn=12; sides=segs(10);  // Returns: 12
 781//   $fa=2; $fs=3, sides=segs(10);  // Returns: 21
 782function segs(r) = 
 783    $fn>0? ($fn>3? $fn : 3) :
 784    let( r = is_finite(r)? r : 0 )
 785    ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs)));
 786
 787
 788// Module: no_children()
 789// Synopsis: Assert that the calling module does not support children.
 790// Topics: Error Checking
 791// See Also: no_function(), no_module(), req_children()
 792// Usage:
 793//   no_children($children);
 794// Description:
 795//   Assert that the calling module does not support children.  Prints an error message to this effect and fails if children are present,
 796//   as indicated by its argument.
 797// Arguments:
 798//   $children = number of children the module has.  
 799// Example:
 800//   module foo() {
 801//       no_children($children);
 802//   }
 803module no_children(count) {
 804  assert($children==0, "Module no_children() does not support child modules");
 805  if ($parent_modules>0) {
 806      assert(count==0, str("Module ",parent_module(1),"() does not support child modules"));
 807  }
 808}
 809
 810
 811// Module: req_children()
 812// Synopsis: Assert that the calling module requires children.
 813// Topics: Error Checking
 814// See Also: no_function(), no_module()
 815// Usage:
 816//   req_children($children);
 817// Description:
 818//   Assert that the calling module requires children.  Prints an error message and fails if no
 819//   children are present as indicated by its argument.
 820// Arguments:
 821//   $children = number of children the module has.  
 822// Example:
 823//   module foo() {
 824//       req_children($children);
 825//   }
 826module req_children(count) {
 827  assert($children==0, "Module no_children() does not support child modules");
 828  if ($parent_modules>0) {
 829      assert(count>0, str("Module ",parent_module(1),"() requires children"));
 830  }
 831}
 832
 833
 834// Function: no_function()
 835// Synopsis: Assert that the argument exists only as a module and not as a function.
 836// Topics: Error Checking
 837// See Also: no_children(), no_module()
 838// Usage:
 839//   dummy = no_function(name)
 840// Description:
 841//   Asserts that the function, "name", only exists as a module.
 842// Example:
 843//   x = no_function("foo");
 844function no_function(name) =
 845   assert(false,str("You called ",name,"() as a function, but it is available only as a module"));
 846
 847
 848// Module: no_module()
 849// Synopsis: Assert that the argument exists only as a function and not as a module.
 850// Topics: Error Checking
 851// See Also: no_children(), no_function()
 852// Usage:
 853//   no_module();
 854// Description:
 855//   Asserts that the called module exists only as a function.
 856// Example:
 857//   module foo() { no_module(); }
 858module no_module() {
 859    assert(false, str("You called ",parent_module(1),"() as a module but it is available only as a function"));
 860}    
 861  
 862
 863// Module: deprecate()
 864// Synopsis: Display a console note that a module is deprecated and suggest a replacement.
 865// Topics: Error Checking
 866// See Also: no_function(), no_module()
 867// Usage:
 868//   deprecate(new_name);
 869// Description:
 870//   Display info that the current module is deprecated and you should switch to a new name
 871// Arguments:
 872//   new_name = name of the new module that replaces the old one
 873module deprecate(new_name)
 874{
 875   echo(str("***** Module ",parent_module(1),"() has been replaced by ",new_name,"() and will be removed in a future version *****"));
 876}   
 877
 878
 879// Section: Testing Helpers
 880
 881
 882function _valstr(x) =
 883    is_string(x)? str("\"",str_replace_char(x, "\"", "\\\""),"\"") :
 884    is_list(x)? str("[",str_join([for (xx=x) _valstr(xx)],","),"]") :
 885    is_num(x) && x==floor(x)? format_int(x) :
 886    is_finite(x)? format_float(x,12) : x;
 887
 888
 889// Module: assert_approx()
 890// Synopsis: Assert that a value is approximately what was expected.
 891// Topics: Error Checking, Debugging
 892// See Also: no_children(), no_function(), no_module(), assert_equal()
 893// Usage:
 894//   assert_approx(got, expected, [info]);
 895// Description:
 896//   Tests if the value gotten is what was expected, plus or minus 1e-9.  If not, then
 897//   the expected and received values are printed to the console and
 898//   an assertion is thrown to stop execution.
 899//   Returns false if both 'got' and 'expected' are 'nan'.
 900// Arguments:
 901//   got = The value actually received.
 902//   expected = The value that was expected.
 903//   info = Extra info to print out to make the error clearer.
 904// Example:
 905//   assert_approx(1/3, 0.333333333333333, str("number=",1,", denom=",3));
 906module assert_approx(got, expected, info) {
 907    no_children($children);
 908    if (!approx(got, expected)) {
 909        echo();
 910        echo(str("EXPECT: ", _valstr(expected)));
 911        echo(str("GOT   : ", _valstr(got)));
 912        if (same_shape(got, expected)) {
 913            echo(str("DELTA : ", _valstr(got - expected)));
 914        }
 915        if (is_def(info)) {
 916            echo(str("INFO  : ", _valstr(info)));
 917        }
 918        assert(approx(got, expected));
 919    }
 920}
 921
 922
 923// Module: assert_equal()
 924// Synopsis: Assert that a value is expected.
 925// See Also: no_children(), no_function(), no_module(), assert_approx()
 926// Topics: Error Checking, Debugging
 927// Usage:
 928//   assert_equal(got, expected, [info]);
 929// Description:
 930//   Tests if the value gotten is what was expected.  If not, then the expected and received values
 931//   are printed to the console and an assertion is thrown to stop execution.
 932//   Returns true if both 'got' and 'expected' are 'nan'.
 933// Arguments:
 934//   got = The value actually received.
 935//   expected = The value that was expected.
 936//   info = Extra info to print out to make the error clearer.
 937// Example:
 938//   assert_approx(3*9, 27, str("a=",3,", b=",9));
 939module assert_equal(got, expected, info) {
 940    no_children($children);
 941    if (got != expected || (is_nan(got) && is_nan(expected))) {
 942        echo();
 943        echo(str("EXPECT: ", _valstr(expected)));
 944        echo(str("GOT   : ", _valstr(got)));
 945        if (same_shape(got, expected)) {
 946            echo(str("DELTA : ", _valstr(got - expected)));
 947        }
 948        if (is_def(info)) {
 949            echo(str("INFO  : ", _valstr(info)));
 950        }
 951        assert(got == expected);
 952    }
 953}
 954
 955
 956// Module: shape_compare()
 957// Synopsis: Compares two child shapes.
 958// SynTags: Geom
 959// Topics: Error Checking, Debugging, Testing
 960// See Also: assert_approx(), assert_equal()
 961// Usage:
 962//   shape_compare([eps]) {TEST_SHAPE; EXPECTED_SHAPE;}
 963// Description:
 964//   Compares two child shapes, returning empty geometry if they are very nearly the same shape and size.
 965//   Returns the differential geometry if they are not quite the same shape and size.
 966// Arguments:
 967//   eps = The surface of the two shapes must be within this size of each other.  Default: 1/1024
 968// Example:
 969//   $fn=36;
 970//   shape_compare() {
 971//       sphere(d=100);
 972//       rotate_extrude() right_half(planar=true) circle(d=100);
 973//   }
 974module shape_compare(eps=1/1024) {
 975    assert($children==2,"Must give exactly two children");
 976    union() {
 977        difference() {
 978            children(0);
 979            if (eps==0) {
 980                children(1);
 981            } else {
 982                minkowski() {
 983                    children(1);
 984                    spheroid(r=eps, style="octa");
 985                }
 986            }
 987        }
 988        difference() {
 989            children(1);
 990            if (eps==0) {
 991                children(0);
 992            } else {
 993                minkowski() {
 994                    children(0);
 995                    spheroid(r=eps, style="octa");
 996                }
 997            }
 998        }
 999    }
1000}
1001
1002
1003// Section: C-Style For Loop Helpers
1004//   You can use a list comprehension with a C-style for loop to iteratively make a calculation.
1005//   .
1006//   The syntax is: `[for (INIT; CONDITION; NEXT) RETVAL]` where:
1007//   - INIT is zero or more `let()` style assignments that are evaluated exactly one time, before the first loop.
1008//   - CONDITION is an expression evaluated at the start of each loop.  If true, continues with the loop.
1009//   - RETVAL is an expression that returns a list item for each loop.
1010//   - NEXT is one or more `let()` style assignments that is evaluated at the end of each loop.
1011//   .
1012//   Since the INIT phase is only run once, and the CONDITION and RETVAL expressions cannot update
1013//   variables, that means that only the NEXT phase can be used for iterative calculations.
1014//   Unfortunately, the NEXT phase runs *after* the RETVAL expression, which means that you need
1015//   to run the loop one extra time to return the final value.  This tends to make the loop code
1016//   look rather ugly.  The `looping()`, `loop_while()` and `loop_done()` functions
1017//   can make this somewhat more legible.
1018//   .
1019//   ```openscad
1020//   function flat_sum(l) = [
1021//       for (
1022//           i = 0,
1023//           total = 0,
1024//           state = 0;
1025//           
1026//           looping(state);
1027//           
1028//           state = loop_while(state, i < len(l)),
1029//           total = total +
1030//               loop_done(state) ? 0 :
1031//               let( x = l[i] )
1032//               is_list(x) ? flat_sum(x) : x,
1033//           i = i + 1
1034//       ) if (loop_done(state)) total;
1035//   ].x;
1036//   ```
1037
1038
1039// Function: looping()
1040// Synopsis: Returns true if the argument indicates the current C-style loop should continue.
1041// Topics: Iteration
1042// See Also: loop_while(), loop_done()
1043// Usage:
1044//   bool = looping(state);
1045// Description:
1046//   Returns true if the `state` value indicates the current loop should continue.  This is useful
1047//   when using C-style for loops to iteratively calculate a value.  Used with `loop_while()` and
1048//   `loop_done()`.  See [Looping Helpers](section-looping-helpers) for an example.
1049// Arguments:
1050//   state = The loop state value.
1051function looping(state) = state < 2;
1052
1053
1054// Function: loop_while()
1055// Synopsis: Returns true if both arguments indicate the current C-style loop should continue.
1056// Topics: Iteration
1057// See Also: looping(), loop_done()
1058// Usage:
1059//   state = loop_while(state, continue);
1060// Description:
1061//   Given the current `state`, and a boolean `continue` that indicates if the loop should still be
1062//   continuing, returns the updated state value for the the next loop.  This is useful when using
1063//   C-style for loops to iteratively calculate a value.  Used with `looping()` and `loop_done()`.
1064//   See [Looping Helpers](section-looping-helpers) for an example.
1065// Arguments:
1066//   state = The loop state value.
1067//   continue = A boolean value indicating whether the current loop should progress.
1068function loop_while(state, continue) =
1069    state > 0 ? 2 :
1070    continue ? 0 : 1;
1071
1072
1073// Function: loop_done()
1074// Synopsis: Returns true if the argument indicates the current C-style loop is finishing.
1075// Topics: Iteration
1076// See Also: looping(), loop_while()
1077// Usage:
1078//   bool = loop_done(state);
1079// Description:
1080//   Returns true if the `state` value indicates the loop is finishing.  This is useful when using
1081//   C-style for loops to iteratively calculate a value.  Used with `looping()` and `loop_while()`.
1082//   See [Looping Helpers](#5-looping-helpers) for an example.
1083// Arguments:
1084//   state = The loop state value.
1085function loop_done(state) = state > 0;
1086
1087
1088// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap