From 48d30fc686af71e3681b55a5b8f7f803e5827ff3 Mon Sep 17 00:00:00 2001 From: Revar Desmera Date: Wed, 8 Jan 2020 20:43:19 -0800 Subject: [PATCH] Reorganize math.scad --- arrays.scad | 54 ++++++++ common.scad | 22 +++ math.scad | 372 ++++++++++++++++++++++++++++----------------------- version.scad | 2 +- 4 files changed, 278 insertions(+), 172 deletions(-) diff --git a/arrays.scad b/arrays.scad index 52085b2..78a010c 100644 --- a/arrays.scad +++ b/arrays.scad @@ -806,6 +806,38 @@ function subindex(v, idx) = [ ]; +// Function: min_index() +// Usage: +// min_index(vals,[all]); +// Description: +// Returns the index of the first occurrence of the minimum value in the given list. +// If `all` is true then returns a list of all indices where the minimum value occurs. +// Arguments: +// vals = vector of values +// all = set to true to return indices of all occurences of the minimum. Default: false +// Example: +// min_index([5,3,9,6,2,7,8,2,1]); // Returns: 4 +// min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7] +function min_index(vals, all=false) = + all ? search(min(vals),vals,0) : search(min(vals), vals)[0]; + + +// Function: max_index() +// Usage: +// max_index(vals,[all]); +// Description: +// Returns the index of the first occurrence of the maximum value in the given list. +// If `all` is true then returns a list of all indices where the maximum value occurs. +// Arguments: +// vals = vector of values +// all = set to true to return indices of all occurences of the maximum. Default: false +// Example: +// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2 +// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7] +function max_index(vals, all=false) = + all ? search(max(vals),vals,0) : search(max(vals), vals)[0]; + + // Function: pair() // Usage: // pair(v) @@ -858,6 +890,28 @@ function triplet_wrap(v) = [for (i=[0:1:len(v)-1]) [v[i],v[(i+1)%len(v)],v[(i+2)%len(v)]]]; +// Function: permute() +// Usage: +// list = permute(l, [n]); +// Description: +// Returns an ordered list of every unique permutation of `n` items out of the given list `l`. +// For the list `[1,2,3,4]`, with `n=2`, this will return `[[1,2], [1,3], [1,4], [2,3], [2,4], [3,4]]`. +// For the list `[1,2,3,4]`, with `n=3`, this will return `[[1,2,3], [1,2,4], [1,3,4], [2,3,4]]`. +// Arguments: +// l = The list to provide permutations for. +// n = The number of items in each permutation. Default: 2 +// Example: +// pairs = permute([3,4,5,6]); // Returns: [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]] +// triplets = permute([3,4,5,6],n=3); // Returns: [[3,4,5],[3,4,6],[3,5,6],[4,5,6]] +// Example(2D): +// for (p=permute(regular_ngon(n=7,d=100))) stroke(p); +function permute(l,n=2,_s=0) = + assert(is_list(l)) + assert(len(l)-_s >= n) + n==1? [for (i=[_s:1:len(l)-1]) [l[i]]] : + [for (i=[_s:1:len(l)-n], p=permute(l,n=n-1,_s=i+1)) concat([l[i]], p)]; + + // Function: zip() // Usage: // zip(v1, v2, v3, [fit], [fill]); diff --git a/common.scad b/common.scad index f63abdb..2761025 100644 --- a/common.scad +++ b/common.scad @@ -64,6 +64,16 @@ function is_def(x) = !is_undef(x); function is_str(x) = is_string(x); +// Function: is_int() +// Usage: +// 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); + + + // Section: Handling `undef`s. @@ -184,4 +194,16 @@ function scalar_vec3(v, dflt=undef) = !is_undef(dflt)? [v,dflt,dflt] : [v,v,v]; +// Function: segs() +// Usage: +// sides = segs(r); +// Description: +// 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) = + $fn>0? ($fn>3? $fn : 3) : + ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs))); + + // vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/math.scad b/math.scad index caa8159..4678d1f 100644 --- a/math.scad +++ b/math.scad @@ -15,7 +15,138 @@ PHI = (1+sqrt(5))/2; // The golden ratio phi. EPSILON = 1e-9; // A really small value useful in comparing FP numbers. ie: abs(a-b)0? ($fn>3? $fn : 3) : - ceil(max(5, min(360/$fa, abs(r)*2*PI/$fs))); +// Computes the Greatest Common Divisor/Factor of `a` and `b`. +function gcd(a,b) = + assert(is_int(a) && is_int(b),"Arguments to gcd must be integers") + b==0 ? abs(a) : gcd(b,a % b); -// Function: lerp() -// Description: Interpolate between two values or vectors. -// Arguments: -// a = First value. -// b = Second value. -// u = The proportion from `a` to `b` to calculate. Valid range is 0.0 to 1.0, inclusive. If given as a list or range of values, returns a list of results. -function lerp(a,b,u) = - is_num(u)? (1-u)*a + u*b : - [for (v = u) lerp(a,b,v)]; +// Computes lcm for two scalars +function _lcm(a,b) = + assert(is_int(a), "Invalid non-integer parameters to lcm") + assert(is_int(b), "Invalid non-integer parameters to lcm") + assert(a!=0 && b!=0, "Arguments to lcm must be nonzero") + abs(a*b) / gcd(a,b); -// Function: hypot() -// Description: Calculate hypotenuse length of a 2D or 3D triangle. -// Arguments: -// x = Length on the X axis. -// y = Length on the Y axis. -// z = Length on the Z axis. -function hypot(x,y,z=0) = - norm([x,y,z]); +// Computes lcm for a list of values +function _lcmlist(a) = + len(a)==1 ? a[0] : + _lcmlist(concat(slice(a,0,len(a)-2),[lcm(a[len(a)-2],a[len(a)-1])])); -// Function: sinh() -// Description: Takes a value `x`, and returns the hyperbolic sine of it. -function sinh(x) = - (exp(x)-exp(-x))/2; +// Function: lcm() +// Usage: +// lcm(a,b) +// lcm(list) +// Description: +// Computes the Least Common Multiple of the two arguments or a list of arguments. Inputs should +// be non-zero integers. The output is always a positive integer. It is an error to pass zero +// as an argument. +function lcm(a,b=[]) = + !is_list(a) && !is_list(b) ? _lcm(a,b) : + let( + arglist = concat(_force_list(a),_force_list(b)) + ) + assert(len(arglist)>0,"invalid call to lcm with empty list(s)") + _lcmlist(arglist); -// Function: cosh() -// Description: Takes a value `x`, and returns the hyperbolic cosine of it. -function cosh(x) = - (exp(x)+exp(-x))/2; - - -// Function: tanh() -// Description: Takes a value `x`, and returns the hyperbolic tangent of it. -function tanh(x) = - sinh(x)/cosh(x); - - -// Function: asinh() -// Description: Takes a value `x`, and returns the inverse hyperbolic sine of it. -function asinh(x) = - ln(x+sqrt(x*x+1)); - - -// Function: acosh() -// Description: Takes a value `x`, and returns the inverse hyperbolic cosine of it. -function acosh(x) = - ln(x+sqrt(x*x-1)); - - -// Function: atanh() -// Description: Takes a value `x`, and returns the inverse hyperbolic tangent of it. -function atanh(x) = - ln((1+x)/(1-x))/2; +// Section: Sums, Products, Aggregate Functions. // Function: sum() // Description: @@ -380,7 +429,12 @@ function atanh(x) = // Example: // sum([1,2,3]); // returns 6. // sum([[1,2,3], [3,4,5], [5,6,7]]); // returns [9, 12, 15] -function sum(v, _i=0, _acc=undef) = _i>=len(v)? _acc : sum(v, _i+1, ((_acc==undef)? v[_i] : _acc+v[_i])); +function sum(v, _i=0, _acc=undef) = + _i>=len(v)? _acc : + sum( + v, _i=_i+1, + _acc=v[_i] + (is_undef(_acc)? 0 : _acc) + ); // Function: cumsum() @@ -473,6 +527,9 @@ function product(v, i=0, tot=undef) = i>=len(v)? tot : product(v, i+1, ((tot==un function mean(v) = sum(v)/len(v); + +// Section: Determinants + // Function: det2() // Description: // Optimized function that returns the determinant for the given 2x2 square matrix. @@ -526,8 +583,26 @@ function determinant(M) = ); + // Section: Comparisons and Logic +// Function: approx() +// Usage: +// approx(a,b,[eps]) +// Description: +// Compares two numbers or vectors, and returns true if they are closer than `eps` to each other. +// Arguments: +// a = First value. +// b = Second value. +// eps = The maximum allowed difference between `a` and `b` that will return true. +// Example: +// approx(-0.3333333333,-1/3); // Returns: true +// approx(0.3333333333,1/3); // Returns: true +// approx(0.3333,1/3); // Returns: false +// approx(0.3333,1/3,eps=1e-3); // Returns: true +// approx(PI,3.1415926536); // Returns: true +function approx(a,b,eps=EPSILON) = let(c=a-b) (is_num(c)? abs(c) : norm(c)) <= eps; + function _type_num(x) = is_undef(x)? 0 : @@ -648,50 +723,5 @@ function count_true(l, nmax=undef, i=0, cnt=0) = ) ); -// If argument is a list return it. Otherwise return a singleton list containing the argument. -function _force_list(x) = is_list(x) ? x : [x]; - -// Function: gcd() -// Usage: -// gcd(a,b) -// Description: -// Computes the greatest common divisor of `a` and `b`. -function gcd(a,b) = - assert(is_integer(a) && is_integer(b),"Arguments to gcd must be integers") - b==0 ? abs(a) : gcd(b,a % b); - -// Computes lcm for two scalars -function _lcm(a,b) = - let( - parmok = is_integer(a) && is_integer(b), - dummy=assert(parmok,"Invalid non-integer parameters to lcm") - assert(a!=0 && b!=0, "Arguments to lcm must be nonzero") - ) - abs(a*b) / gcd(a,b); - -// Computes lcm for a list of values -function _lcmlist(a) = - len(a)==1 ? a[0] : _lcmlist(concat(slice(a,0,len(a)-2),[lcm(a[len(a)-2],a[len(a)-1])])); - -// Function: lcm() -// Usage: -// lcm(a,b) -// lcm(list) -// Description: Computes the least common multiple of the two arguments or a list of arguments. Inputs should be -// nonzero integers. The output is always a positive integer. It is an error to pass zero as an argument. -function lcm(a,b=[]) = - !is_list(a) && !is_list(b) ? _lcm(a,b) : - let( - arglist = concat(_force_list(a),_force_list(b)) - ) - assert(len(arglist)>0,"invalid call to lcm with empty list(s)") - _lcmlist(arglist); - -// Function: is_integer() -// Usage: -// is_integer(n) -// Description: returns true if the given value is an integer (it is a number and it rounds to itself). -function is_integer(n) = is_num(n) && n == round(n); - // vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/version.scad b/version.scad index c2e126c..62186d2 100644 --- a/version.scad +++ b/version.scad @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,74]; +BOSL_VERSION = [2,0,75]; // Section: BOSL Library Version Functions