From 39b4b7282d7b582600dd9df5d5ee11ebf5b7be55 Mon Sep 17 00:00:00 2001
From: RonaldoCMP <rcmpersiano@gmail.com>
Date: Fri, 24 Jul 2020 00:04:16 +0100
Subject: [PATCH] Update typeof(), int(), range(), list_of() and segs

---
 common.scad            | 31 ++++++++++++++++++++-----------
 tests/test_common.scad | 27 ++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/common.scad b/common.scad
index 8d0655a..6cc910e 100644
--- a/common.scad
+++ b/common.scad
@@ -15,7 +15,8 @@
 // Usage:
 //   typ = typeof(x);
 // Description:
-//   Returns a string representing the type of the value.  One of "undef", "boolean", "number", "nan", "string", "list", or "range"
+//   Returns a string representing the type of the value.  One of "undef", "boolean", "number", "nan", "string", "list", "range" or "invalid".
+//   Some malformed "ranges", like '[0:NAN:INF]' and '[0:"a":INF]', may be classified as "undef" or "invalid".
 function typeof(x) =
     is_undef(x)? "undef" :
     is_bool(x)? "boolean" :
@@ -23,8 +24,11 @@ function typeof(x) =
     is_nan(x)? "nan" :
     is_string(x)? "string" :
     is_list(x)? "list" :
-    "range";
+    is_range(x) ? "range" :
+    "invalid";
 
+//***
+// included "invalid"
 
 // Function: is_type()
 // Usage:
@@ -70,8 +74,8 @@ function is_str(x) = is_string(x);
 //   is_int(n)
 // Description:
 //   Returns true if the given value is an integer (it is a number and it rounds to itself).  
-function is_int(n) = is_num(n) && n == round(n);
-function is_integer(n) = is_num(n) && n == round(n);
+function is_int(n) = is_finite(n) && n == round(n);
+function is_integer(n) = is_finite(n) && n == round(n);
 
 
 // Function: is_nan()
@@ -93,7 +97,7 @@ function is_finite(v) = is_num(0*v);
 // Function: is_range()
 // Description:
 //   Returns true if its argument is a range
-function is_range(x) = is_num(x[0]) && !is_list(x);
+function is_range(x) = !is_list(x) && is_finite(x[0]+x[1]+x[2]) ;
 
 
 // Function: is_list_of()
@@ -106,13 +110,15 @@ function is_range(x) = is_num(x[0]) && !is_list(x);
 //   is_list_of([3,4,5], 0);            // Returns true
 //   is_list_of([3,4,undef], 0);        // Returns false
 //   is_list_of([[3,4],[4,5]], [1,1]);  // Returns true
+//   is_list_of([[3,"a"],[4,true]], [1,undef]);  // Returns true
 //   is_list_of([[3,4], 6, [4,5]], [1,1]);  // Returns false
-//   is_list_of([[1,[3,4]], [4,[5,6]]], [1,[2,3]]);    // Returne true
-//   is_list_of([[1,[3,INF]], [4,[5,6]]], [1,[2,3]]);  // Returne false
+//   is_list_of([[1,[3,4]], [4,[5,6]]], [1,[2,3]]);    // Returns true
+//   is_list_of([[1,[3,INF]], [4,[5,6]]], [1,[2,3]]);  // Returns false
+//   is_list_of([], [1,[2,3]]);                        // Returns true
 function is_list_of(list,pattern) =
     let(pattern = 0*pattern)
     is_list(list) &&
-    []==[for(entry=list) if (entry*0 != pattern) entry];
+    []==[for(entry=0*list) if (entry != pattern) entry];
 
 
 // Function: is_consistent()
@@ -311,10 +317,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.
-function segs(r) =
+function segs(r) = 
     $fn>0? ($fn>3? $fn : 3) :
-    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))) ;
 
+//***
+// avoids undef
 
 
 // Section: Testing Helpers
@@ -322,7 +331,7 @@ function segs(r) =
 
 function _valstr(x) =
     is_list(x)? str("[",str_join([for (xx=x) _valstr(xx)],","),"]") :
-    is_num(x)? fmt_float(x,12) : x;
+    is_finite(x)? fmt_float(x,12) : x;
 
 
 // Module: assert_approx()
diff --git a/tests/test_common.scad b/tests/test_common.scad
index ed97cae..1cad5e3 100644
--- a/tests/test_common.scad
+++ b/tests/test_common.scad
@@ -1,4 +1,4 @@
-include <BOSL2/std.scad>
+include <../std.scad>
 
 
 module test_typeof() {
@@ -18,6 +18,10 @@ module test_typeof() {
     assert(typeof([0:1:5]) == "range");
     assert(typeof([-3:2:5]) == "range");
     assert(typeof([10:-2:-10]) == "range");
+    assert(typeof([0:NAN:INF]) == "invalid");
+    assert(typeof([0:"a":INF]) == "undef"); 
+    assert(typeof([0:[]:INF]) == "undef"); 
+    assert(typeof([true:1:INF]) == "undef"); 
 }
 test_typeof();
 
@@ -102,6 +106,8 @@ module test_is_int() {
     assert(!is_int(-99.1));
     assert(!is_int(99.1));
     assert(!is_int(undef));
+    assert(!is_int(INF));
+    assert(!is_int(NAN));
     assert(!is_int(false));
     assert(!is_int(true));
     assert(!is_int("foo"));
@@ -124,6 +130,8 @@ module test_is_integer() {
     assert(!is_integer(-99.1));
     assert(!is_integer(99.1));
     assert(!is_integer(undef));
+    assert(!is_integer(INF));
+    assert(!is_integer(NAN));
     assert(!is_integer(false));
     assert(!is_integer(true));
     assert(!is_integer("foo"));
@@ -166,6 +174,9 @@ module test_is_range() {
     assert(!is_range("foo"));
     assert(!is_range([]));
     assert(!is_range([3,4,5]));
+    assert(!is_range([INF:4:5]));
+    assert(!is_range([3:NAN:5]));
+    assert(!is_range([3:4:"a"]));
     assert(is_range([3:1:5]));
 }
 test_is_nan();
@@ -331,11 +342,25 @@ module test_scalar_vec3() {
     assert(scalar_vec3([3]) == [3,0,0]);
     assert(scalar_vec3([3,4]) == [3,4,0]);
     assert(scalar_vec3([3,4],dflt=1) == [3,4,1]);
+    assert(scalar_vec3([3,"a"],dflt=1) == [3,"a",1]);
+    assert(scalar_vec3([3,[2]],dflt=1) == [3,[2],1]);
     assert(scalar_vec3([3],dflt=1) == [3,1,1]);
     assert(scalar_vec3([3,4,5]) == [3,4,5]);
     assert(scalar_vec3([3,4,5,6]) == [3,4,5]);
+    assert(scalar_vec3([3,4,5,6]) == [3,4,5]);
 }
 test_scalar_vec3();
 
 
+module test_segs() {
+    assert_equal(segs(50,$fn=8), 8);
+    assert_equal(segs(50,$fa=2,$fs=2), 158);
+    assert(segs(1)==5);
+    assert(segs(11)==30);
+  //  assert(segs(1/0)==5);
+  //  assert(segs(0/0)==5);
+  //  assert(segs(undef)==5);
+}
+test_segs();
+
 // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap