From b2121fbfb361363ec658523c95fbf24e6c2b9ba2 Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Mon, 7 Sep 2020 23:10:39 -0700 Subject: [PATCH] Added all_nonzero(). Added is_vector(all_nonzero=). --- math.scad | 42 +++++++++++++++++++++++++++++++---------- tests/test_math.scad | 24 +++++++++++++++++++++++ tests/test_vectors.scad | 8 ++++++++ vectors.scad | 18 +++++++++++------- version.scad | 2 +- 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/math.scad b/math.scad index 10b7463..935c44a 100644 --- a/math.scad +++ b/math.scad @@ -905,7 +905,7 @@ function norm_fro(A) = // Usage: // all_zero(x); // Description: -// Returns true if the number passed to it is approximately zero, to within `eps`. +// Returns true if the finite number passed to it is approximately zero, to within `eps`. // If passed a list, recursively checks if all items in the list are approximately zero. // Otherwise, returns false. // Arguments: @@ -917,8 +917,30 @@ function norm_fro(A) = // all_zero([0,0,0]); // Returns: true. // all_zero([0,0,1e-3]); // Returns: false. function all_zero(x, eps=EPSILON) = + is_finite(x)? approx(x,eps) : is_list(x)? (x != [] && [for (xx=x) if(!all_zero(xx,eps=eps)) 1] == []) : - is_num(x)? approx(x,eps) : + false; + + +// Function: all_nonzero() +// Usage: +// all_nonzero(x); +// Description: +// Returns true if the finite number passed to it is not almost zero, to within `eps`. +// If passed a list, recursively checks if all items in the list are not almost zero. +// Otherwise, returns false. +// Arguments: +// x = The value to check. +// eps = The maximum allowed variance. Default: `EPSILON` (1e-9) +// Example: +// all_nonzero(0); // Returns: false. +// all_nonzero(1e-3); // Returns: true. +// all_nonzero([0,0,0]); // Returns: false. +// all_nonzero([0,0,1e-3]); // Returns: false. +// all_nonzero([1e-3,1e-3,1e-3]); // Returns: true. +function all_nonzero(x, eps=EPSILON) = + is_finite(x)? !approx(x,eps) : + is_list(x)? (x != [] && [for (xx=x) if(!all_nonzero(xx,eps=eps)) 1] == []) : false; @@ -926,7 +948,7 @@ function all_zero(x, eps=EPSILON) = // Usage: // all_positive(x); // Description: -// Returns true if the number passed to it is greater than zero. +// Returns true if the finite number passed to it is greater than zero. // If passed a list, recursively checks if all items in the list are positive. // Otherwise, returns false. // Arguments: @@ -940,8 +962,8 @@ function all_zero(x, eps=EPSILON) = // all_positive([3,1,2]); // Returns: true. // all_positive([3,-1,2]); // Returns: false. function all_positive(x) = - is_list(x)? (x != [] && [for (xx=x) if(!all_positive(xx)) 1] == []) : is_num(x)? x>0 : + is_list(x)? (x != [] && [for (xx=x) if(!all_positive(xx)) 1] == []) : false; @@ -949,7 +971,7 @@ function all_positive(x) = // Usage: // all_negative(x); // Description: -// Returns true if the number passed to it is less than zero. +// Returns true if the finite number passed to it is less than zero. // If passed a list, recursively checks if all items in the list are negative. // Otherwise, returns false. // Arguments: @@ -964,8 +986,8 @@ function all_positive(x) = // all_negative([3,-1,2]); // Returns: false. // all_negative([-3,-1,-2]); // Returns: true. function all_negative(x) = - is_list(x)? (x != [] && [for (xx=x) if(!all_negative(xx)) 1] == []) : is_num(x)? x<0 : + is_list(x)? (x != [] && [for (xx=x) if(!all_negative(xx)) 1] == []) : false; @@ -973,7 +995,7 @@ function all_negative(x) = // Usage: // all_nonpositive(x); // Description: -// Returns true if the number passed to it is less than or equal to zero. +// Returns true if the finite number passed to it is less than or equal to zero. // If passed a list, recursively checks if all items in the list are nonpositive. // Otherwise, returns false. // Arguments: @@ -988,8 +1010,8 @@ function all_negative(x) = // all_nonpositive([3,-1,2]); // Returns: false. // all_nonpositive([-3,-1,-2]); // Returns: true. function all_nonpositive(x) = - is_list(x)? (x != [] && [for (xx=x) if(!all_nonpositive(xx)) 1] == []) : is_num(x)? x<=0 : + is_list(x)? (x != [] && [for (xx=x) if(!all_nonpositive(xx)) 1] == []) : false; @@ -997,7 +1019,7 @@ function all_nonpositive(x) = // Usage: // all_nonnegative(x); // Description: -// Returns true if the number passed to it is greater than or equal to zero. +// Returns true if the finite number passed to it is greater than or equal to zero. // If passed a list, recursively checks if all items in the list are nonnegative. // Otherwise, returns false. // Arguments: @@ -1013,8 +1035,8 @@ function all_nonpositive(x) = // all_nonnegative([3,-1,2]); // Returns: false. // all_nonnegative([-3,-1,-2]); // Returns: false. function all_nonnegative(x) = - is_list(x)? (x != [] && [for (xx=x) if(!all_nonnegative(xx)) 1] == []) : is_num(x)? x>=0 : + is_list(x)? (x != [] && [for (xx=x) if(!all_nonnegative(xx)) 1] == []) : false; diff --git a/tests/test_math.scad b/tests/test_math.scad index 720235c..5641416 100644 --- a/tests/test_math.scad +++ b/tests/test_math.scad @@ -122,6 +122,30 @@ module test_all_zero() { test_all_zero(); +module test_all_nonzero() { + assert(!all_nonzero(0)); + assert(!all_nonzero([0,0,0])); + assert(!all_nonzero([[0,0,0],[0,0]])); + assert(!all_nonzero([EPSILON/2,EPSILON/2,EPSILON/2])); + assert(all_nonzero(1e-3)); + assert(!all_nonzero([0,0,1e-3])); + assert(!all_nonzero([EPSILON*10,0,0])); + assert(!all_nonzero([0,EPSILON*10,0])); + assert(!all_nonzero([0,0,EPSILON*10])); + assert(all_nonzero([1e-3,1e-3,1e-3])); + assert(all_nonzero([EPSILON*10,EPSILON*10,EPSILON*10])); + assert(!all_nonzero(true)); + assert(!all_nonzero(false)); + assert(!all_nonzero(INF)); + assert(!all_nonzero(-INF)); + assert(!all_nonzero(NAN)); + assert(!all_nonzero("foo")); + assert(!all_nonzero([])); + assert(!all_nonzero([0:1:2])); +} +test_all_nonzero(); + + module test_all_positive() { assert(!all_positive(-2)); assert(!all_positive(0)); diff --git a/tests/test_vectors.scad b/tests/test_vectors.scad index 743112f..2e00705 100644 --- a/tests/test_vectors.scad +++ b/tests/test_vectors.scad @@ -14,6 +14,14 @@ module test_is_vector() { assert(is_vector([0,0,0],zero=false) == false); assert(is_vector([0,1,0],zero=true) == false); assert(is_vector([0,0,1],zero=false) == true); + assert(is_vector([1,1,1],zero=false) == true); + + assert(is_vector([0,0,0],all_nonzero=true) == false); + assert(is_vector([0,1,0],all_nonzero=true) == false); + assert(is_vector([0,0,1],all_nonzero=true) == false); + assert(is_vector([1,1,1],all_nonzero=true) == true); + assert(is_vector([-1,1,1],all_nonzero=true) == true); + assert(is_vector([-1,-1,-1],all_nonzero=true) == true); } test_is_vector(); diff --git a/vectors.scad b/vectors.scad index 1749981..3b83eda 100644 --- a/vectors.scad +++ b/vectors.scad @@ -19,7 +19,8 @@ // Arguments: // v = The value to test to see if it is a vector. // length = If given, make sure the vector is `length` items long. -// zero = If false, require that the length of the vector is not approximately zero. If true, require the length of the vector to be approximately zero-length. Default: `undef` (don't check vector length.) +// zero = If false, require that the length/`norm()` of the vector is not approximately zero. If true, require the length/`norm()` of the vector to be approximately zero-length. Default: `undef` (don't check vector length/`norm()`.) +// all_nonzero = If true, requires all elements of the vector to be more than `eps` different from zero. Default: `false` // eps = The minimum vector length that is considered non-zero. Default: `EPSILON` (`1e-9`) // Example: // is_vector(4); // Returns false @@ -30,14 +31,17 @@ // is_vector([3,4,5],3); // Returns true // is_vector([3,4,5],4); // Returns true // is_vector([]); // Returns false -// is_vector([0,4,0],3,zero=false); // Returns true -// is_vector([0,0,0],zero=false); // Returns false -// is_vector([0,0,1e-12],zero=false); // Returns false -// is_vector([],zero=false); // Returns false -function is_vector(v,length,zero,eps=EPSILON) = +// is_vector([0,4,0],3,zero=false); // Returns true +// is_vector([0,0,0],zero=false); // Returns false +// is_vector([0,0,1e-12],zero=false); // Returns false +// is_vector([0,1,0],all_nonzero=false); // Returns false +// is_vector([1,1,1],all_nonzero=false); // Returns true +// is_vector([],zero=false); // Returns false +function is_vector(v, length, zero, all_nonzero=false, eps=EPSILON) = is_list(v) && is_num(0*(v*v)) && (is_undef(length) || len(v)==length) - && (is_undef(zero) || ((norm(v) >= eps) == !zero)); + && (is_undef(zero) || ((norm(v) >= eps) == !zero)) + && (!all_nonzero || all_nonzero(v)) ; // Function: vang() diff --git a/version.scad b/version.scad index 86a9e2e..2ca6341 100644 --- a/version.scad +++ b/version.scad @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,420]; +BOSL_VERSION = [2,0,421]; // Section: BOSL Library Version Functions