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