mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
various file reorgs
This commit is contained in:
parent
4e11ac94f2
commit
b9ae9e9a8b
10 changed files with 1403 additions and 1383 deletions
30
color.scad
30
color.scad
|
@ -98,17 +98,17 @@ module rainbow(list, stride=1, maxhues, shuffle=false, seed)
|
||||||
hues = shuffle ? shuffle(huelist, seed=seed) : huelist;
|
hues = shuffle ? shuffle(huelist, seed=seed) : huelist;
|
||||||
for($idx=idx(list)) {
|
for($idx=idx(list)) {
|
||||||
$item = list[$idx];
|
$item = list[$idx];
|
||||||
HSV(h=hues[$idx]) children();
|
hsv(h=hues[$idx]) children();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Section: Colorspace Conversion
|
// Section: Colorspace Conversion
|
||||||
|
|
||||||
// Function&Module: HSL()
|
// Function&Module: hsl()
|
||||||
// Usage:
|
// Usage:
|
||||||
// HSL(h,[s],[l],[a]) ...
|
// hsl(h,[s],[l],[a]) ...
|
||||||
// rgb = HSL(h,[s],[l],[a]);
|
// rgb = hsl(h,[s],[l],[a]);
|
||||||
// Description:
|
// Description:
|
||||||
// When called as a function, returns the [R,G,B] color for the given hue `h`, saturation `s`, and lightness `l` from the HSL colorspace. If you supply
|
// When called as a function, returns the [R,G,B] color for the given hue `h`, saturation `s`, and lightness `l` from the HSL colorspace. If you supply
|
||||||
// the `a` value then you'll get a length 4 list [R,G,B,A].
|
// the `a` value then you'll get a length 4 list [R,G,B,A].
|
||||||
|
@ -119,11 +119,11 @@ module rainbow(list, stride=1, maxhues, shuffle=false, seed)
|
||||||
// l = The lightness, between 0 and 1. 0 = black, 0.5 = bright colors, 1 = white. Default: 0.5
|
// l = The lightness, between 0 and 1. 0 = black, 0.5 = bright colors, 1 = white. Default: 0.5
|
||||||
// a = Specifies the alpha channel as a value between 0 and 1. 0 = fully transparent, 1=opaque. Default: 1
|
// a = Specifies the alpha channel as a value between 0 and 1. 0 = fully transparent, 1=opaque. Default: 1
|
||||||
// Example:
|
// Example:
|
||||||
// HSL(h=120,s=1,l=0.5) sphere(d=60);
|
// hsl(h=120,s=1,l=0.5) sphere(d=60);
|
||||||
// Example:
|
// Example:
|
||||||
// rgb = HSL(h=270,s=0.75,l=0.6);
|
// rgb = hsl(h=270,s=0.75,l=0.6);
|
||||||
// color(rgb) cube(60, center=true);
|
// color(rgb) cube(60, center=true);
|
||||||
function HSL(h,s=1,l=0.5,a) =
|
function hsl(h,s=1,l=0.5,a) =
|
||||||
let(
|
let(
|
||||||
h=posmod(h,360)
|
h=posmod(h,360)
|
||||||
) [
|
) [
|
||||||
|
@ -133,13 +133,13 @@ function HSL(h,s=1,l=0.5,a) =
|
||||||
if (is_def(a)) a
|
if (is_def(a)) a
|
||||||
];
|
];
|
||||||
|
|
||||||
module HSL(h,s=1,l=0.5,a=1) color(HSL(h,s,l),a) children();
|
module hsl(h,s=1,l=0.5,a=1) color(hsl(h,s,l),a) children();
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: HSV()
|
// Function&Module: hsv()
|
||||||
// Usage:
|
// Usage:
|
||||||
// HSV(h,[s],[v],[a]) ...
|
// hsv(h,[s],[v],[a]) ...
|
||||||
// rgb = HSV(h,[s],[v],[a]);
|
// rgb = hsv(h,[s],[v],[a]);
|
||||||
// Description:
|
// Description:
|
||||||
// When called as a function, returns the [R,G,B] color for the given hue `h`, saturation `s`, and value `v` from the HSV colorspace. If you supply
|
// When called as a function, returns the [R,G,B] color for the given hue `h`, saturation `s`, and value `v` from the HSV colorspace. If you supply
|
||||||
// the `a` value then you'll get a length 4 list [R,G,B,A].
|
// the `a` value then you'll get a length 4 list [R,G,B,A].
|
||||||
|
@ -150,11 +150,11 @@ module HSL(h,s=1,l=0.5,a=1) color(HSL(h,s,l),a) children();
|
||||||
// v = The value, between 0 and 1. 0 = darkest black, 1 = bright. Default: 1
|
// v = The value, between 0 and 1. 0 = darkest black, 1 = bright. Default: 1
|
||||||
// a = Specifies the alpha channel as a value between 0 and 1. 0 = fully transparent, 1=opaque. Default: 1
|
// a = Specifies the alpha channel as a value between 0 and 1. 0 = fully transparent, 1=opaque. Default: 1
|
||||||
// Example:
|
// Example:
|
||||||
// HSV(h=120,s=1,v=1) sphere(d=60);
|
// hsv(h=120,s=1,v=1) sphere(d=60);
|
||||||
// Example:
|
// Example:
|
||||||
// rgb = HSV(h=270,s=0.75,v=0.9);
|
// rgb = hsv(h=270,s=0.75,v=0.9);
|
||||||
// color(rgb) cube(60, center=true);
|
// color(rgb) cube(60, center=true);
|
||||||
function HSV(h,s=1,v=1,a) =
|
function hsv(h,s=1,v=1,a) =
|
||||||
assert(s>=0 && s<=1)
|
assert(s>=0 && s<=1)
|
||||||
assert(v>=0 && v<=1)
|
assert(v>=0 && v<=1)
|
||||||
assert(is_undef(a) || a>=0 && a<=1)
|
assert(is_undef(a) || a>=0 && a<=1)
|
||||||
|
@ -175,7 +175,7 @@ function HSV(h,s=1,v=1,a) =
|
||||||
is_def(a) ? point4d(add_scalar(rgbprime,m),a)
|
is_def(a) ? point4d(add_scalar(rgbprime,m),a)
|
||||||
: add_scalar(rgbprime,m);
|
: add_scalar(rgbprime,m);
|
||||||
|
|
||||||
module HSV(h,s=1,v=1,a=1) color(HSV(h,s,v),a) children();
|
module hsv(h,s=1,v=1,a=1) color(hsv(h,s,v),a) children();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
1534
gears.scad
1534
gears.scad
File diff suppressed because it is too large
Load diff
25
lists.scad
25
lists.scad
|
@ -377,29 +377,6 @@ function repeat(val, n, i=0) =
|
||||||
[for (j=[1:1:n[i]]) repeat(val, n, i+1)];
|
[for (j=[1:1:n[i]]) repeat(val, n, i+1)];
|
||||||
|
|
||||||
|
|
||||||
// Function: count()
|
|
||||||
// Usage:
|
|
||||||
// list = count(n, [s], [step], [reverse]);
|
|
||||||
// Description:
|
|
||||||
// Creates a list of `n` numbers, starting at `s`, incrementing by `step` each time.
|
|
||||||
// You can also pass a list for n and then the length of the input list is used.
|
|
||||||
// Arguments:
|
|
||||||
// n = The length of the list of numbers to create, or a list to match the length of
|
|
||||||
// s = The starting value of the list of numbers.
|
|
||||||
// step = The amount to increment successive numbers in the list.
|
|
||||||
// reverse = Reverse the list. Default: false.
|
|
||||||
// See Also: idx()
|
|
||||||
// Example:
|
|
||||||
// nl1 = count(5); // Returns: [0,1,2,3,4]
|
|
||||||
// nl2 = count(5,3); // Returns: [3,4,5,6,7]
|
|
||||||
// nl3 = count(4,3,2); // Returns: [3,5,7,9]
|
|
||||||
// nl4 = count(5,reverse=true); // Returns: [4,3,2,1,0]
|
|
||||||
// nl5 = count(5,3,reverse=true); // Returns: [7,6,5,4,3]
|
|
||||||
function count(n,s=0,step=1,reverse=false) = let(n=is_list(n) ? len(n) : n)
|
|
||||||
reverse? [for (i=[n-1:-1:0]) s+i*step]
|
|
||||||
: [for (i=[0:1:n-1]) s+i*step];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: list_bset()
|
// Function: list_bset()
|
||||||
// Usage:
|
// Usage:
|
||||||
|
@ -967,7 +944,7 @@ function permutations(l,n=2) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Changing list structure
|
// Section: Changing List Structure
|
||||||
|
|
||||||
|
|
||||||
// Function: list_to_matrix()
|
// Function: list_to_matrix()
|
||||||
|
|
864
math.scad
864
math.scad
|
@ -1,10 +1,13 @@
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// LibFile: math.scad
|
// LibFile: math.scad
|
||||||
// Math helper functions.
|
// Assorted math functions, including linear interpolation, list operations (sums, mean, products),
|
||||||
|
// convolution, quantization, log2, hyperbolic trig functions, random numbers, derivatives,
|
||||||
|
// polynomials, and root finding.
|
||||||
// Includes:
|
// Includes:
|
||||||
// include <BOSL2/std.scad>
|
// include <BOSL2/std.scad>
|
||||||
// FileGroup: Math
|
// FileGroup: Math
|
||||||
// FileSummary: General miscellaneous math function.
|
// FileSummary: Math on lists, special functions, quantization, random numbers, calculus, root finding
|
||||||
|
//
|
||||||
// FileFootnotes: STD=Included in std.scad
|
// FileFootnotes: STD=Included in std.scad
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -28,7 +31,97 @@ NAN = acos(2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Simple math
|
// Section: Interpolation and Counting
|
||||||
|
|
||||||
|
|
||||||
|
// Function: count()
|
||||||
|
// Usage:
|
||||||
|
// list = count(n, [s], [step], [reverse]);
|
||||||
|
// Description:
|
||||||
|
// Creates a list of `n` numbers, starting at `s`, incrementing by `step` each time.
|
||||||
|
// You can also pass a list for n and then the length of the input list is used.
|
||||||
|
// Arguments:
|
||||||
|
// n = The length of the list of numbers to create, or a list to match the length of
|
||||||
|
// s = The starting value of the list of numbers.
|
||||||
|
// step = The amount to increment successive numbers in the list.
|
||||||
|
// reverse = Reverse the list. Default: false.
|
||||||
|
// See Also: idx()
|
||||||
|
// Example:
|
||||||
|
// nl1 = count(5); // Returns: [0,1,2,3,4]
|
||||||
|
// nl2 = count(5,3); // Returns: [3,4,5,6,7]
|
||||||
|
// nl3 = count(4,3,2); // Returns: [3,5,7,9]
|
||||||
|
// nl4 = count(5,reverse=true); // Returns: [4,3,2,1,0]
|
||||||
|
// nl5 = count(5,3,reverse=true); // Returns: [7,6,5,4,3]
|
||||||
|
function count(n,s=0,step=1,reverse=false) = let(n=is_list(n) ? len(n) : n)
|
||||||
|
reverse? [for (i=[n-1:-1:0]) s+i*step]
|
||||||
|
: [for (i=[0:1:n-1]) s+i*step];
|
||||||
|
|
||||||
|
|
||||||
|
// Function: lerp()
|
||||||
|
// Usage:
|
||||||
|
// x = lerp(a, b, u);
|
||||||
|
// l = lerp(a, b, LIST);
|
||||||
|
// Description:
|
||||||
|
// Interpolate between two values or vectors.
|
||||||
|
// If `u` is given as a number, returns the single interpolated value.
|
||||||
|
// If `u` is 0.0, then the value of `a` is returned.
|
||||||
|
// If `u` is 1.0, then the value of `b` is returned.
|
||||||
|
// If `u` is a range, or list of numbers, returns a list of interpolated values.
|
||||||
|
// It is valid to use a `u` value outside the range 0 to 1. The result will be an extrapolation
|
||||||
|
// along the slope formed by `a` and `b`.
|
||||||
|
// Arguments:
|
||||||
|
// a = First value or vector.
|
||||||
|
// b = Second value or vector.
|
||||||
|
// u = The proportion from `a` to `b` to calculate. Standard range is 0.0 to 1.0, inclusive. If given as a list or range of values, returns a list of results.
|
||||||
|
// Example:
|
||||||
|
// x = lerp(0,20,0.3); // Returns: 6
|
||||||
|
// x = lerp(0,20,0.8); // Returns: 16
|
||||||
|
// x = lerp(0,20,-0.1); // Returns: -2
|
||||||
|
// x = lerp(0,20,1.1); // Returns: 22
|
||||||
|
// p = lerp([0,0],[20,10],0.25); // Returns [5,2.5]
|
||||||
|
// l = lerp(0,20,[0.4,0.6]); // Returns: [8,12]
|
||||||
|
// l = lerp(0,20,[0.25:0.25:0.75]); // Returns: [5,10,15]
|
||||||
|
// Example(2D):
|
||||||
|
// p1 = [-50,-20]; p2 = [50,30];
|
||||||
|
// stroke([p1,p2]);
|
||||||
|
// pts = lerp(p1, p2, [0:1/8:1]);
|
||||||
|
// // Points colored in ROYGBIV order.
|
||||||
|
// rainbow(pts) translate($item) circle(d=3,$fn=8);
|
||||||
|
function lerp(a,b,u) =
|
||||||
|
assert(same_shape(a,b), "Bad or inconsistent inputs to lerp")
|
||||||
|
is_finite(u)? (1-u)*a + u*b :
|
||||||
|
assert(is_finite(u) || is_vector(u) || valid_range(u), "Input u to lerp must be a number, vector, or valid range.")
|
||||||
|
[for (v = u) (1-v)*a + v*b ];
|
||||||
|
|
||||||
|
|
||||||
|
// Function: lerpn()
|
||||||
|
// Usage:
|
||||||
|
// x = lerpn(a, b, n);
|
||||||
|
// x = lerpn(a, b, n, [endpoint]);
|
||||||
|
// Description:
|
||||||
|
// Returns exactly `n` values, linearly interpolated between `a` and `b`.
|
||||||
|
// If `endpoint` is true, then the last value will exactly equal `b`.
|
||||||
|
// If `endpoint` is false, then the last value will about `a+(b-a)*(1-1/n)`.
|
||||||
|
// Arguments:
|
||||||
|
// a = First value or vector.
|
||||||
|
// b = Second value or vector.
|
||||||
|
// n = The number of values to return.
|
||||||
|
// endpoint = If true, the last value will be exactly `b`. If false, the last value will be one step less.
|
||||||
|
// Example:
|
||||||
|
// l = lerpn(-4,4,9); // Returns: [-4,-3,-2,-1,0,1,2,3,4]
|
||||||
|
// l = lerpn(-4,4,8,false); // Returns: [-4,-3,-2,-1,0,1,2,3]
|
||||||
|
// l = lerpn(0,1,6); // Returns: [0, 0.2, 0.4, 0.6, 0.8, 1]
|
||||||
|
// l = lerpn(0,1,5,false); // Returns: [0, 0.2, 0.4, 0.6, 0.8]
|
||||||
|
function lerpn(a,b,n,endpoint=true) =
|
||||||
|
assert(same_shape(a,b), "Bad or inconsistent inputs to lerpn")
|
||||||
|
assert(is_int(n))
|
||||||
|
assert(is_bool(endpoint))
|
||||||
|
let( d = n - (endpoint? 1 : 0) )
|
||||||
|
[for (i=[0:1:n-1]) let(u=i/d) (1-u)*a + u*b];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Section: Miscellaneous Functions
|
||||||
|
|
||||||
// Function: sqr()
|
// Function: sqr()
|
||||||
// Usage:
|
// Usage:
|
||||||
|
@ -139,124 +232,45 @@ function binomial_coefficient(n,k) =
|
||||||
b[len(b)-1];
|
b[len(b)-1];
|
||||||
|
|
||||||
|
|
||||||
// Function: lerp()
|
// Function: gcd()
|
||||||
// Usage:
|
// Usage:
|
||||||
// x = lerp(a, b, u);
|
// x = gcd(a,b)
|
||||||
// l = lerp(a, b, LIST);
|
|
||||||
// Description:
|
// Description:
|
||||||
// Interpolate between two values or vectors.
|
// Computes the Greatest Common Divisor/Factor of `a` and `b`.
|
||||||
// If `u` is given as a number, returns the single interpolated value.
|
function gcd(a,b) =
|
||||||
// If `u` is 0.0, then the value of `a` is returned.
|
assert(is_int(a) && is_int(b),"Arguments to gcd must be integers")
|
||||||
// If `u` is 1.0, then the value of `b` is returned.
|
b==0 ? abs(a) : gcd(b,a % b);
|
||||||
// If `u` is a range, or list of numbers, returns a list of interpolated values.
|
|
||||||
// It is valid to use a `u` value outside the range 0 to 1. The result will be an extrapolation
|
|
||||||
// along the slope formed by `a` and `b`.
|
|
||||||
// Arguments:
|
|
||||||
// a = First value or vector.
|
|
||||||
// b = Second value or vector.
|
|
||||||
// u = The proportion from `a` to `b` to calculate. Standard range is 0.0 to 1.0, inclusive. If given as a list or range of values, returns a list of results.
|
|
||||||
// Example:
|
|
||||||
// x = lerp(0,20,0.3); // Returns: 6
|
|
||||||
// x = lerp(0,20,0.8); // Returns: 16
|
|
||||||
// x = lerp(0,20,-0.1); // Returns: -2
|
|
||||||
// x = lerp(0,20,1.1); // Returns: 22
|
|
||||||
// p = lerp([0,0],[20,10],0.25); // Returns [5,2.5]
|
|
||||||
// l = lerp(0,20,[0.4,0.6]); // Returns: [8,12]
|
|
||||||
// l = lerp(0,20,[0.25:0.25:0.75]); // Returns: [5,10,15]
|
|
||||||
// Example(2D):
|
|
||||||
// p1 = [-50,-20]; p2 = [50,30];
|
|
||||||
// stroke([p1,p2]);
|
|
||||||
// pts = lerp(p1, p2, [0:1/8:1]);
|
|
||||||
// // Points colored in ROYGBIV order.
|
|
||||||
// rainbow(pts) translate($item) circle(d=3,$fn=8);
|
|
||||||
function lerp(a,b,u) =
|
|
||||||
assert(same_shape(a,b), "Bad or inconsistent inputs to lerp")
|
|
||||||
is_finite(u)? (1-u)*a + u*b :
|
|
||||||
assert(is_finite(u) || is_vector(u) || valid_range(u), "Input u to lerp must be a number, vector, or valid range.")
|
|
||||||
[for (v = u) (1-v)*a + v*b ];
|
|
||||||
|
|
||||||
|
|
||||||
// Function: lerpn()
|
// Computes lcm for two integers
|
||||||
|
function _lcm(a,b) =
|
||||||
|
assert(is_int(a) && is_int(b), "Invalid non-integer parameters to lcm")
|
||||||
|
assert(a!=0 && b!=0, "Arguments to lcm should not be zero")
|
||||||
|
abs(a*b) / gcd(a,b);
|
||||||
|
|
||||||
|
|
||||||
|
// Computes lcm for a list of values
|
||||||
|
function _lcmlist(a) =
|
||||||
|
len(a)==1 ? a[0] :
|
||||||
|
_lcmlist(concat(lcm(a[0],a[1]),list_tail(a,2)));
|
||||||
|
|
||||||
|
|
||||||
|
// Function: lcm()
|
||||||
// Usage:
|
// Usage:
|
||||||
// x = lerpn(a, b, n);
|
// div = lcm(a, b);
|
||||||
// x = lerpn(a, b, n, [endpoint]);
|
// divs = lcm(list);
|
||||||
// Description:
|
// Description:
|
||||||
// Returns exactly `n` values, linearly interpolated between `a` and `b`.
|
// Computes the Least Common Multiple of the two arguments or a list of arguments. Inputs should
|
||||||
// If `endpoint` is true, then the last value will exactly equal `b`.
|
// be non-zero integers. The output is always a positive integer. It is an error to pass zero
|
||||||
// If `endpoint` is false, then the last value will about `a+(b-a)*(1-1/n)`.
|
// as an argument.
|
||||||
// Arguments:
|
function lcm(a,b=[]) =
|
||||||
// a = First value or vector.
|
!is_list(a) && !is_list(b)
|
||||||
// b = Second value or vector.
|
? _lcm(a,b)
|
||||||
// n = The number of values to return.
|
: let( arglist = concat(force_list(a),force_list(b)) )
|
||||||
// endpoint = If true, the last value will be exactly `b`. If false, the last value will be one step less.
|
assert(len(arglist)>0, "Invalid call to lcm with empty list(s)")
|
||||||
// Example:
|
_lcmlist(arglist);
|
||||||
// l = lerpn(-4,4,9); // Returns: [-4,-3,-2,-1,0,1,2,3,4]
|
|
||||||
// l = lerpn(-4,4,8,false); // Returns: [-4,-3,-2,-1,0,1,2,3]
|
|
||||||
// l = lerpn(0,1,6); // Returns: [0, 0.2, 0.4, 0.6, 0.8, 1]
|
|
||||||
// l = lerpn(0,1,5,false); // Returns: [0, 0.2, 0.4, 0.6, 0.8]
|
|
||||||
function lerpn(a,b,n,endpoint=true) =
|
|
||||||
assert(same_shape(a,b), "Bad or inconsistent inputs to lerpn")
|
|
||||||
assert(is_int(n))
|
|
||||||
assert(is_bool(endpoint))
|
|
||||||
let( d = n - (endpoint? 1 : 0) )
|
|
||||||
[for (i=[0:1:n-1]) let(u=i/d) (1-u)*a + u*b];
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Undef Safe Math
|
|
||||||
|
|
||||||
// Function: u_add()
|
|
||||||
// Usage:
|
|
||||||
// x = u_add(a, b);
|
|
||||||
// Description:
|
|
||||||
// Adds `a` to `b`, returning the result, or undef if either value is `undef`.
|
|
||||||
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
|
||||||
// Arguments:
|
|
||||||
// a = First value.
|
|
||||||
// b = Second value.
|
|
||||||
function u_add(a,b) = is_undef(a) || is_undef(b)? undef : a + b;
|
|
||||||
|
|
||||||
|
|
||||||
// Function: u_sub()
|
|
||||||
// Usage:
|
|
||||||
// x = u_sub(a, b);
|
|
||||||
// Description:
|
|
||||||
// Subtracts `b` from `a`, returning the result, or undef if either value is `undef`.
|
|
||||||
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
|
||||||
// Arguments:
|
|
||||||
// a = First value.
|
|
||||||
// b = Second value.
|
|
||||||
function u_sub(a,b) = is_undef(a) || is_undef(b)? undef : a - b;
|
|
||||||
|
|
||||||
|
|
||||||
// Function: u_mul()
|
|
||||||
// Usage:
|
|
||||||
// x = u_mul(a, b);
|
|
||||||
// Description:
|
|
||||||
// Multiplies `a` by `b`, returning the result, or undef if either value is `undef`.
|
|
||||||
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
|
||||||
// Arguments:
|
|
||||||
// a = First value.
|
|
||||||
// b = Second value.
|
|
||||||
function u_mul(a,b) =
|
|
||||||
is_undef(a) || is_undef(b)? undef :
|
|
||||||
is_vector(a) && is_vector(b)? v_mul(a,b) :
|
|
||||||
a * b;
|
|
||||||
|
|
||||||
|
|
||||||
// Function: u_div()
|
|
||||||
// Usage:
|
|
||||||
// x = u_div(a, b);
|
|
||||||
// Description:
|
|
||||||
// Divides `a` by `b`, returning the result, or undef if either value is `undef`.
|
|
||||||
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
|
||||||
// Arguments:
|
|
||||||
// a = First value.
|
|
||||||
// b = Second value.
|
|
||||||
function u_div(a,b) =
|
|
||||||
is_undef(a) || is_undef(b)? undef :
|
|
||||||
is_vector(a) && is_vector(b)? v_div(a,b) :
|
|
||||||
a / b;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Hyperbolic Trigonometry
|
// Section: Hyperbolic Trigonometry
|
||||||
|
@ -488,6 +502,228 @@ function modang(x) =
|
||||||
let(xx = posmod(x,360)) xx<180? xx : xx-360;
|
let(xx = posmod(x,360)) xx<180? xx : xx-360;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Section: Operations on Lists (Sums, Mean, Products)
|
||||||
|
|
||||||
|
// Function: sum()
|
||||||
|
// Usage:
|
||||||
|
// x = sum(v, [dflt]);
|
||||||
|
// Description:
|
||||||
|
// Returns the sum of all entries in the given consistent list.
|
||||||
|
// If passed an array of vectors, returns the sum the vectors.
|
||||||
|
// If passed an array of matrices, returns the sum of the matrices.
|
||||||
|
// If passed an empty list, the value of `dflt` will be returned.
|
||||||
|
// Arguments:
|
||||||
|
// v = The list to get the sum of.
|
||||||
|
// dflt = The default value to return if `v` is an empty list. Default: 0
|
||||||
|
// Example:
|
||||||
|
// sum([1,2,3]); // returns 6.
|
||||||
|
// sum([[1,2,3], [3,4,5], [5,6,7]]); // returns [9, 12, 15]
|
||||||
|
function sum(v, dflt=0) =
|
||||||
|
v==[]? dflt :
|
||||||
|
assert(is_consistent(v), "Input to sum is non-numeric or inconsistent")
|
||||||
|
is_finite(v[0]) || is_vector(v[0]) ? [for(i=v) 1]*v :
|
||||||
|
_sum(v,v[0]*0);
|
||||||
|
|
||||||
|
function _sum(v,_total,_i=0) = _i>=len(v) ? _total : _sum(v,_total+v[_i], _i+1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: mean()
|
||||||
|
// Usage:
|
||||||
|
// x = mean(v);
|
||||||
|
// Description:
|
||||||
|
// Returns the arithmetic mean/average of all entries in the given array.
|
||||||
|
// If passed a list of vectors, returns a vector of the mean of each part.
|
||||||
|
// Arguments:
|
||||||
|
// v = The list of values to get the mean of.
|
||||||
|
// Example:
|
||||||
|
// mean([2,3,4]); // returns 3.
|
||||||
|
// mean([[1,2,3], [3,4,5], [5,6,7]]); // returns [3, 4, 5]
|
||||||
|
function mean(v) =
|
||||||
|
assert(is_list(v) && len(v)>0, "Invalid list.")
|
||||||
|
sum(v)/len(v);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: median()
|
||||||
|
// Usage:
|
||||||
|
// middle = median(v)
|
||||||
|
// Description:
|
||||||
|
// Returns the median of the given vector.
|
||||||
|
function median(v) =
|
||||||
|
assert(is_vector(v), "Input to median must be a vector")
|
||||||
|
len(v)%2 ? max( list_smallest(v, ceil(len(v)/2)) ) :
|
||||||
|
let( lowest = list_smallest(v, len(v)/2 + 1),
|
||||||
|
max = max(lowest),
|
||||||
|
imax = search(max,lowest,1),
|
||||||
|
max2 = max([for(i=idx(lowest)) if(i!=imax[0]) lowest[i] ])
|
||||||
|
)
|
||||||
|
(max+max2)/2;
|
||||||
|
|
||||||
|
|
||||||
|
// Function: deltas()
|
||||||
|
// Usage:
|
||||||
|
// delts = deltas(v);
|
||||||
|
// Description:
|
||||||
|
// Returns a list with the deltas of adjacent entries in the given list, optionally wrapping back to the front.
|
||||||
|
// The list should be a consistent list of numeric components (numbers, vectors, matrix, etc).
|
||||||
|
// Given [a,b,c,d], returns [b-a,c-b,d-c].
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// v = The list to get the deltas of.
|
||||||
|
// wrap = If true, wrap back to the start from the end. ie: return the difference between the last and first items as the last delta. Default: false
|
||||||
|
// Example:
|
||||||
|
// deltas([2,5,9,17]); // returns [3,4,8].
|
||||||
|
// deltas([[1,2,3], [3,6,8], [4,8,11]]); // returns [[2,4,5], [1,2,3]]
|
||||||
|
function deltas(v, wrap=false) =
|
||||||
|
assert( is_consistent(v) && len(v)>1 , "Inconsistent list or with length<=1.")
|
||||||
|
[for (p=pair(v,wrap)) p[1]-p[0]] ;
|
||||||
|
|
||||||
|
|
||||||
|
// Function: cumsum()
|
||||||
|
// Usage:
|
||||||
|
// sums = cumsum(v);
|
||||||
|
// Description:
|
||||||
|
// Returns a list where each item is the cumulative sum of all items up to and including the corresponding entry in the input list.
|
||||||
|
// If passed an array of vectors, returns a list of cumulative vectors sums.
|
||||||
|
// Arguments:
|
||||||
|
// v = The list to get the sum of.
|
||||||
|
// Example:
|
||||||
|
// cumsum([1,1,1]); // returns [1,2,3]
|
||||||
|
// cumsum([2,2,2]); // returns [2,4,6]
|
||||||
|
// cumsum([1,2,3]); // returns [1,3,6]
|
||||||
|
// cumsum([[1,2,3], [3,4,5], [5,6,7]]); // returns [[1,2,3], [4,6,8], [9,12,15]]
|
||||||
|
function cumsum(v) =
|
||||||
|
assert(is_consistent(v), "The input is not consistent." )
|
||||||
|
len(v)<=1 ? v :
|
||||||
|
_cumsum(v,_i=1,_acc=[v[0]]);
|
||||||
|
|
||||||
|
function _cumsum(v,_i=0,_acc=[]) =
|
||||||
|
_i>=len(v) ? _acc :
|
||||||
|
_cumsum( v, _i+1, [ each _acc, _acc[len(_acc)-1] + v[_i] ] );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: product()
|
||||||
|
// Usage:
|
||||||
|
// x = product(v);
|
||||||
|
// Description:
|
||||||
|
// Returns the product of all entries in the given list.
|
||||||
|
// If passed a list of vectors of same dimension, returns a vector of products of each part.
|
||||||
|
// If passed a list of square matrices, returns the resulting product matrix.
|
||||||
|
// Arguments:
|
||||||
|
// v = The list to get the product of.
|
||||||
|
// Example:
|
||||||
|
// product([2,3,4]); // returns 24.
|
||||||
|
// product([[1,2,3], [3,4,5], [5,6,7]]); // returns [15, 48, 105]
|
||||||
|
function product(v) =
|
||||||
|
assert( is_vector(v) || is_matrix(v) || ( is_matrix(v[0],square=true) && is_consistent(v)),
|
||||||
|
"Invalid input.")
|
||||||
|
_product(v, 1, v[0]);
|
||||||
|
|
||||||
|
function _product(v, i=0, _tot) =
|
||||||
|
i>=len(v) ? _tot :
|
||||||
|
_product( v,
|
||||||
|
i+1,
|
||||||
|
( is_vector(v[i])? v_mul(_tot,v[i]) : _tot*v[i] ) );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: cumprod()
|
||||||
|
// Description:
|
||||||
|
// Returns a list where each item is the cumulative product of all items up to and including the corresponding entry in the input list.
|
||||||
|
// If passed an array of vectors, returns a list of elementwise vector products. If passed a list of square matrices returns matrix
|
||||||
|
// products multiplying on the left, so a list `[A,B,C]` will produce the output `[A,BA,CBA]`.
|
||||||
|
// Arguments:
|
||||||
|
// list = The list to get the product of.
|
||||||
|
// Example:
|
||||||
|
// cumprod([1,3,5]); // returns [1,3,15]
|
||||||
|
// cumprod([2,2,2]); // returns [2,4,8]
|
||||||
|
// cumprod([[1,2,3], [3,4,5], [5,6,7]])); // returns [[1, 2, 3], [3, 8, 15], [15, 48, 105]]
|
||||||
|
function cumprod(list) =
|
||||||
|
is_vector(list) ? _cumprod(list) :
|
||||||
|
assert(is_consistent(list), "Input must be a consistent list of scalars, vectors or square matrices")
|
||||||
|
is_matrix(list[0]) ? assert(len(list[0])==len(list[0][0]), "Matrices must be square") _cumprod(list)
|
||||||
|
: _cumprod_vec(list);
|
||||||
|
|
||||||
|
function _cumprod(v,_i=0,_acc=[]) =
|
||||||
|
_i==len(v) ? _acc :
|
||||||
|
_cumprod(
|
||||||
|
v, _i+1,
|
||||||
|
concat(
|
||||||
|
_acc,
|
||||||
|
[_i==0 ? v[_i] : v[_i]*_acc[len(_acc)-1]]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
function _cumprod_vec(v,_i=0,_acc=[]) =
|
||||||
|
_i==len(v) ? _acc :
|
||||||
|
_cumprod_vec(
|
||||||
|
v, _i+1,
|
||||||
|
concat(
|
||||||
|
_acc,
|
||||||
|
[_i==0 ? v[_i] : v_mul(_acc[len(_acc)-1],v[_i])]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: convolve()
|
||||||
|
// Usage:
|
||||||
|
// x = convolve(p,q);
|
||||||
|
// Description:
|
||||||
|
// Given two vectors, or one vector and a path or
|
||||||
|
// two paths of the same dimension, finds the convolution of them.
|
||||||
|
// If both parameter are vectors, returns the vector convolution.
|
||||||
|
// If one parameter is a vector and the other a path,
|
||||||
|
// convolves using products by scalars and returns a path.
|
||||||
|
// If both parameters are paths, convolve using scalar products
|
||||||
|
// and returns a vector.
|
||||||
|
// The returned vector or path has length len(p)+len(q)-1.
|
||||||
|
// Arguments:
|
||||||
|
// p = The first vector or path.
|
||||||
|
// q = The second vector or path.
|
||||||
|
// Example:
|
||||||
|
// a = convolve([1,1],[1,2,1]); // Returns: [1,3,3,1]
|
||||||
|
// b = convolve([1,2,3],[1,2,1])); // Returns: [1,4,8,8,3]
|
||||||
|
// c = convolve([[1,1],[2,2],[3,1]],[1,2,1])); // Returns: [[1,1],[4,4],[8,6],[8,4],[3,1]]
|
||||||
|
// d = convolve([[1,1],[2,2],[3,1]],[[1,2],[2,1]])); // Returns: [3,9,11,7]
|
||||||
|
function convolve(p,q) =
|
||||||
|
p==[] || q==[] ? [] :
|
||||||
|
assert( (is_vector(p) || is_matrix(p))
|
||||||
|
&& ( is_vector(q) || (is_matrix(q) && ( !is_vector(p[0]) || (len(p[0])==len(q[0])) ) ) ) ,
|
||||||
|
"The inputs should be vectors or paths all of the same dimension.")
|
||||||
|
let( n = len(p),
|
||||||
|
m = len(q))
|
||||||
|
[for(i=[0:n+m-2], k1 = max(0,i-n+1), k2 = min(i,m-1) )
|
||||||
|
sum([for(j=[k1:k2]) p[i-j]*q[j] ])
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: sum_of_sines()
|
||||||
|
// Usage:
|
||||||
|
// sum_of_sines(a,sines)
|
||||||
|
// Description:
|
||||||
|
// Gives the sum of a series of sines, at a given angle.
|
||||||
|
// Arguments:
|
||||||
|
// a = Angle to get the value for.
|
||||||
|
// sines = List of [amplitude, frequency, offset] items, where the frequency is the number of times the cycle repeats around the circle.
|
||||||
|
// Example:
|
||||||
|
// v = sum_of_sines(30, [[10,3,0], [5,5.5,60]]);
|
||||||
|
function sum_of_sines(a, sines) =
|
||||||
|
assert( is_finite(a) && is_matrix(sines,undef,3), "Invalid input.")
|
||||||
|
sum([ for (s = sines)
|
||||||
|
let(
|
||||||
|
ss=point3d(s),
|
||||||
|
v=ss[0]*sin(a*ss[1]+ss[2])
|
||||||
|
) v
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Random Number Generation
|
// Section: Random Number Generation
|
||||||
|
|
||||||
// Function: rand_int()
|
// Function: rand_int()
|
||||||
|
@ -635,407 +871,6 @@ function random_polygon(n=3,size=1, seed) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: GCD/GCF, LCM
|
|
||||||
|
|
||||||
// Function: gcd()
|
|
||||||
// Usage:
|
|
||||||
// x = gcd(a,b)
|
|
||||||
// Description:
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
|
|
||||||
// Computes lcm for two integers
|
|
||||||
function _lcm(a,b) =
|
|
||||||
assert(is_int(a) && is_int(b), "Invalid non-integer parameters to lcm")
|
|
||||||
assert(a!=0 && b!=0, "Arguments to lcm should not be zero")
|
|
||||||
abs(a*b) / gcd(a,b);
|
|
||||||
|
|
||||||
|
|
||||||
// Computes lcm for a list of values
|
|
||||||
function _lcmlist(a) =
|
|
||||||
len(a)==1 ? a[0] :
|
|
||||||
_lcmlist(concat(lcm(a[0],a[1]),list_tail(a,2)));
|
|
||||||
|
|
||||||
|
|
||||||
// Function: lcm()
|
|
||||||
// Usage:
|
|
||||||
// div = lcm(a, b);
|
|
||||||
// divs = 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);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Sums, Products, Aggregate Functions.
|
|
||||||
|
|
||||||
// Function: sum()
|
|
||||||
// Usage:
|
|
||||||
// x = sum(v, [dflt]);
|
|
||||||
// Description:
|
|
||||||
// Returns the sum of all entries in the given consistent list.
|
|
||||||
// If passed an array of vectors, returns the sum the vectors.
|
|
||||||
// If passed an array of matrices, returns the sum of the matrices.
|
|
||||||
// If passed an empty list, the value of `dflt` will be returned.
|
|
||||||
// Arguments:
|
|
||||||
// v = The list to get the sum of.
|
|
||||||
// dflt = The default value to return if `v` is an empty list. Default: 0
|
|
||||||
// Example:
|
|
||||||
// sum([1,2,3]); // returns 6.
|
|
||||||
// sum([[1,2,3], [3,4,5], [5,6,7]]); // returns [9, 12, 15]
|
|
||||||
function sum(v, dflt=0) =
|
|
||||||
v==[]? dflt :
|
|
||||||
assert(is_consistent(v), "Input to sum is non-numeric or inconsistent")
|
|
||||||
is_finite(v[0]) || is_vector(v[0]) ? [for(i=v) 1]*v :
|
|
||||||
_sum(v,v[0]*0);
|
|
||||||
|
|
||||||
function _sum(v,_total,_i=0) = _i>=len(v) ? _total : _sum(v,_total+v[_i], _i+1);
|
|
||||||
|
|
||||||
// Function: cumsum()
|
|
||||||
// Usage:
|
|
||||||
// sums = cumsum(v);
|
|
||||||
// Description:
|
|
||||||
// Returns a list where each item is the cumulative sum of all items up to and including the corresponding entry in the input list.
|
|
||||||
// If passed an array of vectors, returns a list of cumulative vectors sums.
|
|
||||||
// Arguments:
|
|
||||||
// v = The list to get the sum of.
|
|
||||||
// Example:
|
|
||||||
// cumsum([1,1,1]); // returns [1,2,3]
|
|
||||||
// cumsum([2,2,2]); // returns [2,4,6]
|
|
||||||
// cumsum([1,2,3]); // returns [1,3,6]
|
|
||||||
// cumsum([[1,2,3], [3,4,5], [5,6,7]]); // returns [[1,2,3], [4,6,8], [9,12,15]]
|
|
||||||
function cumsum(v) =
|
|
||||||
assert(is_consistent(v), "The input is not consistent." )
|
|
||||||
len(v)<=1 ? v :
|
|
||||||
_cumsum(v,_i=1,_acc=[v[0]]);
|
|
||||||
|
|
||||||
function _cumsum(v,_i=0,_acc=[]) =
|
|
||||||
_i>=len(v) ? _acc :
|
|
||||||
_cumsum( v, _i+1, [ each _acc, _acc[len(_acc)-1] + v[_i] ] );
|
|
||||||
|
|
||||||
|
|
||||||
// Function: sum_of_sines()
|
|
||||||
// Usage:
|
|
||||||
// sum_of_sines(a,sines)
|
|
||||||
// Description:
|
|
||||||
// Gives the sum of a series of sines, at a given angle.
|
|
||||||
// Arguments:
|
|
||||||
// a = Angle to get the value for.
|
|
||||||
// sines = List of [amplitude, frequency, offset] items, where the frequency is the number of times the cycle repeats around the circle.
|
|
||||||
// Example:
|
|
||||||
// v = sum_of_sines(30, [[10,3,0], [5,5.5,60]]);
|
|
||||||
function sum_of_sines(a, sines) =
|
|
||||||
assert( is_finite(a) && is_matrix(sines,undef,3), "Invalid input.")
|
|
||||||
sum([ for (s = sines)
|
|
||||||
let(
|
|
||||||
ss=point3d(s),
|
|
||||||
v=ss[0]*sin(a*ss[1]+ss[2])
|
|
||||||
) v
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
|
||||||
// Function: deltas()
|
|
||||||
// Usage:
|
|
||||||
// delts = deltas(v);
|
|
||||||
// Description:
|
|
||||||
// Returns a list with the deltas of adjacent entries in the given list, optionally wrapping back to the front.
|
|
||||||
// The list should be a consistent list of numeric components (numbers, vectors, matrix, etc).
|
|
||||||
// Given [a,b,c,d], returns [b-a,c-b,d-c].
|
|
||||||
//
|
|
||||||
// Arguments:
|
|
||||||
// v = The list to get the deltas of.
|
|
||||||
// wrap = If true, wrap back to the start from the end. ie: return the difference between the last and first items as the last delta. Default: false
|
|
||||||
// Example:
|
|
||||||
// deltas([2,5,9,17]); // returns [3,4,8].
|
|
||||||
// deltas([[1,2,3], [3,6,8], [4,8,11]]); // returns [[2,4,5], [1,2,3]]
|
|
||||||
function deltas(v, wrap=false) =
|
|
||||||
assert( is_consistent(v) && len(v)>1 , "Inconsistent list or with length<=1.")
|
|
||||||
[for (p=pair(v,wrap)) p[1]-p[0]] ;
|
|
||||||
|
|
||||||
|
|
||||||
// Function: product()
|
|
||||||
// Usage:
|
|
||||||
// x = product(v);
|
|
||||||
// Description:
|
|
||||||
// Returns the product of all entries in the given list.
|
|
||||||
// If passed a list of vectors of same dimension, returns a vector of products of each part.
|
|
||||||
// If passed a list of square matrices, returns the resulting product matrix.
|
|
||||||
// Arguments:
|
|
||||||
// v = The list to get the product of.
|
|
||||||
// Example:
|
|
||||||
// product([2,3,4]); // returns 24.
|
|
||||||
// product([[1,2,3], [3,4,5], [5,6,7]]); // returns [15, 48, 105]
|
|
||||||
function product(v) =
|
|
||||||
assert( is_vector(v) || is_matrix(v) || ( is_matrix(v[0],square=true) && is_consistent(v)),
|
|
||||||
"Invalid input.")
|
|
||||||
_product(v, 1, v[0]);
|
|
||||||
|
|
||||||
function _product(v, i=0, _tot) =
|
|
||||||
i>=len(v) ? _tot :
|
|
||||||
_product( v,
|
|
||||||
i+1,
|
|
||||||
( is_vector(v[i])? v_mul(_tot,v[i]) : _tot*v[i] ) );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: cumprod()
|
|
||||||
// Description:
|
|
||||||
// Returns a list where each item is the cumulative product of all items up to and including the corresponding entry in the input list.
|
|
||||||
// If passed an array of vectors, returns a list of elementwise vector products. If passed a list of square matrices returns matrix
|
|
||||||
// products multiplying on the left, so a list `[A,B,C]` will produce the output `[A,BA,CBA]`.
|
|
||||||
// Arguments:
|
|
||||||
// list = The list to get the product of.
|
|
||||||
// Example:
|
|
||||||
// cumprod([1,3,5]); // returns [1,3,15]
|
|
||||||
// cumprod([2,2,2]); // returns [2,4,8]
|
|
||||||
// cumprod([[1,2,3], [3,4,5], [5,6,7]])); // returns [[1, 2, 3], [3, 8, 15], [15, 48, 105]]
|
|
||||||
function cumprod(list) =
|
|
||||||
is_vector(list) ? _cumprod(list) :
|
|
||||||
assert(is_consistent(list), "Input must be a consistent list of scalars, vectors or square matrices")
|
|
||||||
is_matrix(list[0]) ? assert(len(list[0])==len(list[0][0]), "Matrices must be square") _cumprod(list)
|
|
||||||
: _cumprod_vec(list);
|
|
||||||
|
|
||||||
function _cumprod(v,_i=0,_acc=[]) =
|
|
||||||
_i==len(v) ? _acc :
|
|
||||||
_cumprod(
|
|
||||||
v, _i+1,
|
|
||||||
concat(
|
|
||||||
_acc,
|
|
||||||
[_i==0 ? v[_i] : v[_i]*_acc[len(_acc)-1]]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
function _cumprod_vec(v,_i=0,_acc=[]) =
|
|
||||||
_i==len(v) ? _acc :
|
|
||||||
_cumprod_vec(
|
|
||||||
v, _i+1,
|
|
||||||
concat(
|
|
||||||
_acc,
|
|
||||||
[_i==0 ? v[_i] : v_mul(_acc[len(_acc)-1],v[_i])]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Function: mean()
|
|
||||||
// Usage:
|
|
||||||
// x = mean(v);
|
|
||||||
// Description:
|
|
||||||
// Returns the arithmetic mean/average of all entries in the given array.
|
|
||||||
// If passed a list of vectors, returns a vector of the mean of each part.
|
|
||||||
// Arguments:
|
|
||||||
// v = The list of values to get the mean of.
|
|
||||||
// Example:
|
|
||||||
// mean([2,3,4]); // returns 3.
|
|
||||||
// mean([[1,2,3], [3,4,5], [5,6,7]]); // returns [3, 4, 5]
|
|
||||||
function mean(v) =
|
|
||||||
assert(is_list(v) && len(v)>0, "Invalid list.")
|
|
||||||
sum(v)/len(v);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: median()
|
|
||||||
// Usage:
|
|
||||||
// middle = median(v)
|
|
||||||
// Description:
|
|
||||||
// Returns the median of the given vector.
|
|
||||||
function median(v) =
|
|
||||||
assert(is_vector(v), "Input to median must be a vector")
|
|
||||||
len(v)%2 ? max( list_smallest(v, ceil(len(v)/2)) ) :
|
|
||||||
let( lowest = list_smallest(v, len(v)/2 + 1),
|
|
||||||
max = max(lowest),
|
|
||||||
imax = search(max,lowest,1),
|
|
||||||
max2 = max([for(i=idx(lowest)) if(i!=imax[0]) lowest[i] ])
|
|
||||||
)
|
|
||||||
(max+max2)/2;
|
|
||||||
|
|
||||||
|
|
||||||
// Function: convolve()
|
|
||||||
// Usage:
|
|
||||||
// x = convolve(p,q);
|
|
||||||
// Description:
|
|
||||||
// Given two vectors, or one vector and a path or
|
|
||||||
// two paths of the same dimension, finds the convolution of them.
|
|
||||||
// If both parameter are vectors, returns the vector convolution.
|
|
||||||
// If one parameter is a vector and the other a path,
|
|
||||||
// convolves using products by scalars and returns a path.
|
|
||||||
// If both parameters are paths, convolve using scalar products
|
|
||||||
// and returns a vector.
|
|
||||||
// The returned vector or path has length len(p)+len(q)-1.
|
|
||||||
// Arguments:
|
|
||||||
// p = The first vector or path.
|
|
||||||
// q = The second vector or path.
|
|
||||||
// Example:
|
|
||||||
// a = convolve([1,1],[1,2,1]); // Returns: [1,3,3,1]
|
|
||||||
// b = convolve([1,2,3],[1,2,1])); // Returns: [1,4,8,8,3]
|
|
||||||
// c = convolve([[1,1],[2,2],[3,1]],[1,2,1])); // Returns: [[1,1],[4,4],[8,6],[8,4],[3,1]]
|
|
||||||
// d = convolve([[1,1],[2,2],[3,1]],[[1,2],[2,1]])); // Returns: [3,9,11,7]
|
|
||||||
function convolve(p,q) =
|
|
||||||
p==[] || q==[] ? [] :
|
|
||||||
assert( (is_vector(p) || is_matrix(p))
|
|
||||||
&& ( is_vector(q) || (is_matrix(q) && ( !is_vector(p[0]) || (len(p[0])==len(q[0])) ) ) ) ,
|
|
||||||
"The inputs should be vectors or paths all of the same dimension.")
|
|
||||||
let( n = len(p),
|
|
||||||
m = len(q))
|
|
||||||
[for(i=[0:n+m-2], k1 = max(0,i-n+1), k2 = min(i,m-1) )
|
|
||||||
sum([for(j=[k1:k2]) p[i-j]*q[j] ])
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: all_integer()
|
|
||||||
// Usage:
|
|
||||||
// bool = all_integer(x);
|
|
||||||
// Description:
|
|
||||||
// If given a number, returns true if the number is a finite integer.
|
|
||||||
// If given an empty list, returns false. If given a non-empty list, returns
|
|
||||||
// true if every item of the list is an integer. Otherwise, returns false.
|
|
||||||
// Arguments:
|
|
||||||
// x = The value to check.
|
|
||||||
// Example:
|
|
||||||
// b = all_integer(true); // Returns: false
|
|
||||||
// b = all_integer("foo"); // Returns: false
|
|
||||||
// b = all_integer(4); // Returns: true
|
|
||||||
// b = all_integer(4.5); // Returns: false
|
|
||||||
// b = all_integer([]); // Returns: false
|
|
||||||
// b = all_integer([3,4,5]); // Returns: true
|
|
||||||
// b = all_integer([3,4.2,5]); // Returns: false
|
|
||||||
// b = all_integer([3,[4,7],5]); // Returns: false
|
|
||||||
function all_integer(x) =
|
|
||||||
is_num(x)? is_int(x) :
|
|
||||||
is_list(x)? (x != [] && [for (xx=x) if(!is_int(xx)) 1] == []) :
|
|
||||||
false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: any()
|
|
||||||
// Usage:
|
|
||||||
// bool = any(l);
|
|
||||||
// bool = any(l, func); // Requires OpenSCAD 2021.01 or later.
|
|
||||||
// Requirements:
|
|
||||||
// Requires OpenSCAD 2021.01 or later to use the `func=` argument.
|
|
||||||
// Description:
|
|
||||||
// Returns true if any item in list `l` evaluates as true.
|
|
||||||
// Arguments:
|
|
||||||
// l = The list to test for true items.
|
|
||||||
// func = An optional function literal of signature (x), returning bool, to test each list item with.
|
|
||||||
// Example:
|
|
||||||
// any([0,false,undef]); // Returns false.
|
|
||||||
// any([1,false,undef]); // Returns true.
|
|
||||||
// any([1,5,true]); // Returns true.
|
|
||||||
// any([[0,0], [0,0]]); // Returns true.
|
|
||||||
// any([[0,0], [1,0]]); // Returns true.
|
|
||||||
function any(l, func) =
|
|
||||||
assert(is_list(l), "The input is not a list." )
|
|
||||||
assert(func==undef || is_func(func))
|
|
||||||
is_func(func)
|
|
||||||
? _any_func(l, func)
|
|
||||||
: _any_bool(l);
|
|
||||||
|
|
||||||
function _any_func(l, func, i=0, out=false) =
|
|
||||||
i >= len(l) || out? out :
|
|
||||||
_any_func(l, func, i=i+1, out=out || func(l[i]));
|
|
||||||
|
|
||||||
function _any_bool(l, i=0, out=false) =
|
|
||||||
i >= len(l) || out? out :
|
|
||||||
_any_bool(l, i=i+1, out=out || l[i]);
|
|
||||||
|
|
||||||
|
|
||||||
// Function: all()
|
|
||||||
// Usage:
|
|
||||||
// bool = all(l);
|
|
||||||
// bool = all(l, func); // Requires OpenSCAD 2021.01 or later.
|
|
||||||
// Requirements:
|
|
||||||
// Requires OpenSCAD 2021.01 or later to use the `func=` argument.
|
|
||||||
// Description:
|
|
||||||
// Returns true if all items in list `l` evaluate as true. If `func` is given a function liteal
|
|
||||||
// of signature (x), returning bool, then that function literal is evaluated for each list item.
|
|
||||||
// Arguments:
|
|
||||||
// l = The list to test for true items.
|
|
||||||
// func = An optional function literal of signature (x), returning bool, to test each list item with.
|
|
||||||
// Example:
|
|
||||||
// test1 = all([0,false,undef]); // Returns false.
|
|
||||||
// test2 = all([1,false,undef]); // Returns false.
|
|
||||||
// test3 = all([1,5,true]); // Returns true.
|
|
||||||
// test4 = all([[0,0], [0,0]]); // Returns true.
|
|
||||||
// test5 = all([[0,0], [1,0]]); // Returns true.
|
|
||||||
// test6 = all([[1,1], [1,1]]); // Returns true.
|
|
||||||
function all(l, func) =
|
|
||||||
assert(is_list(l), "The input is not a list.")
|
|
||||||
assert(func==undef || is_func(func))
|
|
||||||
is_func(func)
|
|
||||||
? _all_func(l, func)
|
|
||||||
: _all_bool(l);
|
|
||||||
|
|
||||||
function _all_func(l, func, i=0, out=true) =
|
|
||||||
i >= len(l) || !out? out :
|
|
||||||
_all_func(l, func, i=i+1, out=out && func(l[i]));
|
|
||||||
|
|
||||||
function _all_bool(l, i=0, out=true) =
|
|
||||||
i >= len(l) || !out? out :
|
|
||||||
_all_bool(l, i=i+1, out=out && l[i]);
|
|
||||||
|
|
||||||
|
|
||||||
// Function: count_true()
|
|
||||||
// Usage:
|
|
||||||
// seq = count_true(l, [nmax=]);
|
|
||||||
// seq = count_true(l, func, [nmax=]); // Requires OpenSCAD 2021.01 or later.
|
|
||||||
// Requirements:
|
|
||||||
// Requires OpenSCAD 2021.01 or later to use the `func=` argument.
|
|
||||||
// Description:
|
|
||||||
// Returns the number of items in `l` that evaluate as true.
|
|
||||||
// If `l` is a lists of lists, this is applied recursively to each
|
|
||||||
// sublist. Returns the total count of items that evaluate as true
|
|
||||||
// in all recursive sublists.
|
|
||||||
// Arguments:
|
|
||||||
// l = The list to test for true items.
|
|
||||||
// func = An optional function literal of signature (x), returning bool, to test each list item with.
|
|
||||||
// ---
|
|
||||||
// nmax = Max number of true items to count. Default: `undef` (no limit)
|
|
||||||
// Example:
|
|
||||||
// num1 = count_true([0,false,undef]); // Returns 0.
|
|
||||||
// num2 = count_true([1,false,undef]); // Returns 1.
|
|
||||||
// num3 = count_true([1,5,false]); // Returns 2.
|
|
||||||
// num4 = count_true([1,5,true]); // Returns 3.
|
|
||||||
// num5 = count_true([[0,0], [0,0]]); // Returns 2.
|
|
||||||
// num6 = count_true([[0,0], [1,0]]); // Returns 2.
|
|
||||||
// num7 = count_true([[1,1], [1,1]]); // Returns 2.
|
|
||||||
// num8 = count_true([[1,1], [1,1]], nmax=1); // Returns 1.
|
|
||||||
function count_true(l, func, nmax) =
|
|
||||||
assert(is_list(l))
|
|
||||||
assert(func==undef || is_func(func))
|
|
||||||
is_func(func)
|
|
||||||
? _count_true_func(l, func, nmax)
|
|
||||||
: _count_true_bool(l, nmax);
|
|
||||||
|
|
||||||
function _count_true_func(l, func, nmax, i=0, out=0) =
|
|
||||||
i >= len(l) || (nmax!=undef && out>=nmax) ? out :
|
|
||||||
_count_true_func(
|
|
||||||
l, func, nmax, i = i + 1,
|
|
||||||
out = out + (func(l[i])? 1:0)
|
|
||||||
);
|
|
||||||
|
|
||||||
function _count_true_bool(l, nmax, i=0, out=0) =
|
|
||||||
i >= len(l) || (nmax!=undef && out>=nmax) ? out :
|
|
||||||
_count_true_bool(
|
|
||||||
l, nmax, i = i + 1,
|
|
||||||
out = out + (l[i]? 1:0)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Calculus
|
// Section: Calculus
|
||||||
|
|
||||||
// Function: deriv()
|
// Function: deriv()
|
||||||
|
@ -1609,4 +1444,5 @@ function _rootfind(f, xpts, ypts, yrange, tol, i=0) =
|
||||||
: _rootfind(f, xinterval, yinterval, new_yrange, tol, i+1);
|
: _rootfind(f, xinterval, yinterval, new_yrange, tol, i+1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
|
@ -127,7 +127,6 @@ function phillips_diam(size, depth) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Module: torx_mask()
|
// Module: torx_mask()
|
||||||
// Usage:
|
// Usage:
|
||||||
// torx_mask(size, l, [center]);
|
// torx_mask(size, l, [center]);
|
||||||
|
@ -144,7 +143,7 @@ function phillips_diam(size, depth) =
|
||||||
// torx_mask(size=30, l=10, $fa=1, $fs=1);
|
// torx_mask(size=30, l=10, $fa=1, $fs=1);
|
||||||
module torx_mask(size, l=5, center, anchor, spin=0, orient=UP) {
|
module torx_mask(size, l=5, center, anchor, spin=0, orient=UP) {
|
||||||
anchor = get_anchor(anchor, center, BOT, BOT);
|
anchor = get_anchor(anchor, center, BOT, BOT);
|
||||||
od = torx_outer_diam(size);
|
od = torx_diam(size);
|
||||||
attachable(anchor,spin,orient, d=od, l=l) {
|
attachable(anchor,spin,orient, d=od, l=l) {
|
||||||
linear_extrude(height=l, convexity=4, center=true) {
|
linear_extrude(height=l, convexity=4, center=true) {
|
||||||
torx_mask2d(size);
|
torx_mask2d(size);
|
||||||
|
@ -164,10 +163,10 @@ module torx_mask(size, l=5, center, anchor, spin=0, orient=UP) {
|
||||||
// Example(2D):
|
// Example(2D):
|
||||||
// torx_mask2d(size=30, $fa=1, $fs=1);
|
// torx_mask2d(size=30, $fa=1, $fs=1);
|
||||||
module torx_mask2d(size) {
|
module torx_mask2d(size) {
|
||||||
od = torx_outer_diam(size);
|
od = torx_diam(size);
|
||||||
id = torx_inner_diam(size);
|
id = _torx_inner_diam(size);
|
||||||
tip = torx_tip_radius(size);
|
tip = _torx_tip_radius(size);
|
||||||
rounding = torx_rounding_radius(size);
|
rounding = _torx_rounding_radius(size);
|
||||||
base = od - 2*tip;
|
base = od - 2*tip;
|
||||||
$fn = quantup(segs(od/2),12);
|
$fn = quantup(segs(od/2),12);
|
||||||
difference() {
|
difference() {
|
||||||
|
@ -194,13 +193,13 @@ module torx_mask2d(size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Function: torx_outer_diam()
|
// Function: torx_diam()
|
||||||
// Usage:
|
// Usage:
|
||||||
// diam = torx_outer_diam(size);
|
// diam = torx_diam(size);
|
||||||
// Description: Get the typical outer diameter of Torx profile.
|
// Description: Get the typical outer diameter of Torx profile.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// size = Torx size.
|
// size = Torx size.
|
||||||
function torx_outer_diam(size) = lookup(size, [
|
function torx_diam(size) = lookup(size, [
|
||||||
[ 6, 1.75],
|
[ 6, 1.75],
|
||||||
[ 8, 2.40],
|
[ 8, 2.40],
|
||||||
[ 10, 2.80],
|
[ 10, 2.80],
|
||||||
|
@ -220,13 +219,13 @@ function torx_outer_diam(size) = lookup(size, [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
// Function: torx_inner_diam()
|
/// Internal Function: torx_inner_diam()
|
||||||
// Usage:
|
/// Usage:
|
||||||
// diam = torx_inner_diam(size);
|
/// diam = torx_inner_diam(size);
|
||||||
// Description: Get typical inner diameter of Torx profile.
|
/// Description: Get typical inner diameter of Torx profile.
|
||||||
// Arguments:
|
/// Arguments:
|
||||||
// size = Torx size.
|
/// size = Torx size.
|
||||||
function torx_inner_diam(size) = lookup(size, [
|
function _torx_inner_diam(size) = lookup(size, [
|
||||||
[ 6, 1.27],
|
[ 6, 1.27],
|
||||||
[ 8, 1.75],
|
[ 8, 1.75],
|
||||||
[ 10, 2.05],
|
[ 10, 2.05],
|
||||||
|
@ -272,13 +271,13 @@ function torx_depth(size) = lookup(size, [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
// Function: torx_tip_radius()
|
/// Internal Function: torx_tip_radius()
|
||||||
// Usage:
|
/// Usage:
|
||||||
// rad = torx_tip_radius(size);
|
/// rad = torx_tip_radius(size);
|
||||||
// Description: Gets minor rounding radius of Torx profile.
|
/// Description: Gets minor rounding radius of Torx profile.
|
||||||
// Arguments:
|
/// Arguments:
|
||||||
// size = Torx size.
|
/// size = Torx size.
|
||||||
function torx_tip_radius(size) = lookup(size, [
|
function _torx_tip_radius(size) = lookup(size, [
|
||||||
[ 6, 0.132],
|
[ 6, 0.132],
|
||||||
[ 8, 0.190],
|
[ 8, 0.190],
|
||||||
[ 10, 0.229],
|
[ 10, 0.229],
|
||||||
|
@ -298,13 +297,13 @@ function torx_tip_radius(size) = lookup(size, [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
// Function: torx_rounding_radius()
|
/// Internal Function: torx_rounding_radius()
|
||||||
// Usage:
|
/// Usage:
|
||||||
// rad = torx_rounding_radius(size);
|
/// rad = torx_rounding_radius(size);
|
||||||
// Description: Gets major rounding radius of Torx profile.
|
/// Description: Gets major rounding radius of Torx profile.
|
||||||
// Arguments:
|
/// Arguments:
|
||||||
// size = Torx size.
|
/// size = Torx size.
|
||||||
function torx_rounding_radius(size) = lookup(size, [
|
function _torx_rounding_radius(size) = lookup(size, [
|
||||||
[ 6, 0.383],
|
[ 6, 0.383],
|
||||||
[ 8, 0.510],
|
[ 8, 0.510],
|
||||||
[ 10, 0.598],
|
[ 10, 0.598],
|
||||||
|
|
3
tests/README.txt
Normal file
3
tests/README.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
This directory contains regression tests scripts to check whether the
|
||||||
|
library is working correctly. If all the scripts run without
|
||||||
|
producing any output, then all the tests have passed.
|
|
@ -1,7 +1,7 @@
|
||||||
include <../std.scad>
|
include <../std.scad>
|
||||||
|
|
||||||
|
|
||||||
module test_HSL() {
|
module test_hsl() {
|
||||||
for (h = [0:30:360]) {
|
for (h = [0:30:360]) {
|
||||||
for (s = [0:0.2:1]) {
|
for (s = [0:0.2:1]) {
|
||||||
for (l = [0:0.2:1]) {
|
for (l = [0:0.2:1]) {
|
||||||
|
@ -16,15 +16,15 @@ module test_HSL() {
|
||||||
h<=300? [x,0,c] :
|
h<=300? [x,0,c] :
|
||||||
[c,0,x]
|
[c,0,x]
|
||||||
);
|
);
|
||||||
assert_approx(HSL(h,s,l), rgb, format("h={}, s={}, l={}", [h,s,l]));
|
assert_approx(hsl(h,s,l), rgb, format("h={}, s={}, l={}", [h,s,l]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
test_HSL();
|
test_hsl();
|
||||||
|
|
||||||
|
|
||||||
module test_HSV() {
|
module test_hsv() {
|
||||||
for (h = [0:30:360]) {
|
for (h = [0:30:360]) {
|
||||||
for (s = [0:0.2:1]) {
|
for (s = [0:0.2:1]) {
|
||||||
for (v = [0:0.2:1]) {
|
for (v = [0:0.2:1]) {
|
||||||
|
@ -39,12 +39,12 @@ module test_HSV() {
|
||||||
h<=300? [x,0,c] :
|
h<=300? [x,0,c] :
|
||||||
[c,0,x]
|
[c,0,x]
|
||||||
);
|
);
|
||||||
assert_approx(HSV(h,s,v), rgb, format("h={}, s={}, v={}", [h,s,v]));
|
assert_approx(hsv(h,s,v), rgb, format("h={}, s={}, v={}", [h,s,v]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
test_HSV();
|
test_hsv();
|
||||||
|
|
||||||
|
|
||||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
|
@ -2,24 +2,24 @@ include <../std.scad>
|
||||||
include <../screw_drive.scad>
|
include <../screw_drive.scad>
|
||||||
|
|
||||||
|
|
||||||
module test_torx_outer_diam() {
|
module test_torx_diam() {
|
||||||
assert_approx(torx_outer_diam(10), 2.80);
|
assert_approx(torx_diam(10), 2.80);
|
||||||
assert_approx(torx_outer_diam(15), 3.35);
|
assert_approx(torx_diam(15), 3.35);
|
||||||
assert_approx(torx_outer_diam(20), 3.95);
|
assert_approx(torx_diam(20), 3.95);
|
||||||
assert_approx(torx_outer_diam(25), 4.50);
|
assert_approx(torx_diam(25), 4.50);
|
||||||
assert_approx(torx_outer_diam(30), 5.60);
|
assert_approx(torx_diam(30), 5.60);
|
||||||
assert_approx(torx_outer_diam(40), 6.75);
|
assert_approx(torx_diam(40), 6.75);
|
||||||
}
|
}
|
||||||
test_torx_outer_diam();
|
test_torx_diam();
|
||||||
|
|
||||||
|
|
||||||
module test_torx_inner_diam() {
|
module test_torx_inner_diam() {
|
||||||
assert_approx(torx_inner_diam(10), 2.05);
|
assert_approx(_torx_inner_diam(10), 2.05);
|
||||||
assert_approx(torx_inner_diam(15), 2.40);
|
assert_approx(_torx_inner_diam(15), 2.40);
|
||||||
assert_approx(torx_inner_diam(20), 2.85);
|
assert_approx(_torx_inner_diam(20), 2.85);
|
||||||
assert_approx(torx_inner_diam(25), 3.25);
|
assert_approx(_torx_inner_diam(25), 3.25);
|
||||||
assert_approx(torx_inner_diam(30), 4.05);
|
assert_approx(_torx_inner_diam(30), 4.05);
|
||||||
assert_approx(torx_inner_diam(40), 4.85);
|
assert_approx(_torx_inner_diam(40), 4.85);
|
||||||
}
|
}
|
||||||
test_torx_inner_diam();
|
test_torx_inner_diam();
|
||||||
|
|
||||||
|
@ -36,23 +36,23 @@ test_torx_depth();
|
||||||
|
|
||||||
|
|
||||||
module test_torx_tip_radius() {
|
module test_torx_tip_radius() {
|
||||||
assert_approx(torx_tip_radius(10), 0.229);
|
assert_approx(_torx_tip_radius(10), 0.229);
|
||||||
assert_approx(torx_tip_radius(15), 0.267);
|
assert_approx(_torx_tip_radius(15), 0.267);
|
||||||
assert_approx(torx_tip_radius(20), 0.305);
|
assert_approx(_torx_tip_radius(20), 0.305);
|
||||||
assert_approx(torx_tip_radius(25), 0.375);
|
assert_approx(_torx_tip_radius(25), 0.375);
|
||||||
assert_approx(torx_tip_radius(30), 0.451);
|
assert_approx(_torx_tip_radius(30), 0.451);
|
||||||
assert_approx(torx_tip_radius(40), 0.546);
|
assert_approx(_torx_tip_radius(40), 0.546);
|
||||||
}
|
}
|
||||||
test_torx_tip_radius();
|
test_torx_tip_radius();
|
||||||
|
|
||||||
|
|
||||||
module test_torx_rounding_radius() {
|
module test_torx_rounding_radius() {
|
||||||
assert_approx(torx_rounding_radius(10), 0.598);
|
assert_approx(_torx_rounding_radius(10), 0.598);
|
||||||
assert_approx(torx_rounding_radius(15), 0.716);
|
assert_approx(_torx_rounding_radius(15), 0.716);
|
||||||
assert_approx(torx_rounding_radius(20), 0.859);
|
assert_approx(_torx_rounding_radius(20), 0.859);
|
||||||
assert_approx(torx_rounding_radius(25), 0.920);
|
assert_approx(_torx_rounding_radius(25), 0.920);
|
||||||
assert_approx(torx_rounding_radius(30), 1.194);
|
assert_approx(_torx_rounding_radius(30), 1.194);
|
||||||
assert_approx(torx_rounding_radius(40), 1.428);
|
assert_approx(_torx_rounding_radius(40), 1.428);
|
||||||
}
|
}
|
||||||
test_torx_rounding_radius();
|
test_torx_rounding_radius();
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,7 @@ shell2d(thickness=-5,or=[5,0],ir=[5,0]) star(5,step=2,d=100);
|
||||||
## Color Manipulators
|
## Color Manipulators
|
||||||
The built-in OpenSCAD `color()` module can let you set the RGB color of an object, but it's often
|
The built-in OpenSCAD `color()` module can let you set the RGB color of an object, but it's often
|
||||||
easier to select colors using other color schemes. You can use the HSL or Hue-Saturation-Lightness
|
easier to select colors using other color schemes. You can use the HSL or Hue-Saturation-Lightness
|
||||||
color scheme with the `HSL()` module:
|
color scheme with the `hsl()` module:
|
||||||
|
|
||||||
```openscad-3D
|
```openscad-3D
|
||||||
include <BOSL2/std.scad>
|
include <BOSL2/std.scad>
|
||||||
|
@ -295,12 +295,12 @@ n = 10; size = 100/n;
|
||||||
for (a=count(n), b=count(n), c=count(n)) {
|
for (a=count(n), b=count(n), c=count(n)) {
|
||||||
let( h=360*a/n, s=1-b/(n-1), l=c/(n-1))
|
let( h=360*a/n, s=1-b/(n-1), l=c/(n-1))
|
||||||
translate(size*[a,b,c]) {
|
translate(size*[a,b,c]) {
|
||||||
HSL(h,s,l) cube(size);
|
hsl(h,s,l) cube(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can use the HSV or Hue-Saturation-Value color scheme with the `HSV()` module:
|
You can use the HSV or Hue-Saturation-Value color scheme with the `hsv()` module:
|
||||||
|
|
||||||
```openscad-3D
|
```openscad-3D
|
||||||
include <BOSL2/std.scad>
|
include <BOSL2/std.scad>
|
||||||
|
@ -308,7 +308,7 @@ n = 10; size = 100/n;
|
||||||
for (a=count(n), b=count(n), c=count(n)) {
|
for (a=count(n), b=count(n), c=count(n)) {
|
||||||
let( h=360*a/n, s=1-b/(n-1), v=c/(n-1))
|
let( h=360*a/n, s=1-b/(n-1), v=c/(n-1))
|
||||||
translate(size*[a,b,c]) {
|
translate(size*[a,b,c]) {
|
||||||
HSV(h,s,v) cube(size);
|
hsv(h,s,v) cube(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
199
utility.scad
199
utility.scad
|
@ -116,6 +116,30 @@ function is_int(n) = is_finite(n) && n == round(n);
|
||||||
function is_integer(n) = is_finite(n) && n == round(n);
|
function is_integer(n) = is_finite(n) && n == round(n);
|
||||||
|
|
||||||
|
|
||||||
|
// Function: all_integer()
|
||||||
|
// Usage:
|
||||||
|
// bool = all_integer(x);
|
||||||
|
// Description:
|
||||||
|
// If given a number, returns true if the number is a finite integer.
|
||||||
|
// If given an empty list, returns false. If given a non-empty list, returns
|
||||||
|
// true if every item of the list is an integer. Otherwise, returns false.
|
||||||
|
// Arguments:
|
||||||
|
// x = The value to check.
|
||||||
|
// Example:
|
||||||
|
// b = all_integer(true); // Returns: false
|
||||||
|
// b = all_integer("foo"); // Returns: false
|
||||||
|
// b = all_integer(4); // Returns: true
|
||||||
|
// b = all_integer(4.5); // Returns: false
|
||||||
|
// b = all_integer([]); // Returns: false
|
||||||
|
// b = all_integer([3,4,5]); // Returns: true
|
||||||
|
// b = all_integer([3,4.2,5]); // Returns: false
|
||||||
|
// b = all_integer([3,[4,7],5]); // Returns: false
|
||||||
|
function all_integer(x) =
|
||||||
|
is_num(x)? is_int(x) :
|
||||||
|
is_list(x)? (x != [] && [for (xx=x) if(!is_int(xx)) 1] == []) :
|
||||||
|
false;
|
||||||
|
|
||||||
|
|
||||||
// Function: is_nan()
|
// Function: is_nan()
|
||||||
// Usage:
|
// Usage:
|
||||||
// bool = is_nan(x);
|
// bool = is_nan(x);
|
||||||
|
@ -404,6 +428,181 @@ function all_defined(v,recursive=false) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Section: Undef Safe Arithmetic
|
||||||
|
|
||||||
|
// Function: u_add()
|
||||||
|
// Usage:
|
||||||
|
// x = u_add(a, b);
|
||||||
|
// Description:
|
||||||
|
// Adds `a` to `b`, returning the result, or undef if either value is `undef`.
|
||||||
|
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
||||||
|
// Arguments:
|
||||||
|
// a = First value.
|
||||||
|
// b = Second value.
|
||||||
|
function u_add(a,b) = is_undef(a) || is_undef(b)? undef : a + b;
|
||||||
|
|
||||||
|
|
||||||
|
// Function: u_sub()
|
||||||
|
// Usage:
|
||||||
|
// x = u_sub(a, b);
|
||||||
|
// Description:
|
||||||
|
// Subtracts `b` from `a`, returning the result, or undef if either value is `undef`.
|
||||||
|
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
||||||
|
// Arguments:
|
||||||
|
// a = First value.
|
||||||
|
// b = Second value.
|
||||||
|
function u_sub(a,b) = is_undef(a) || is_undef(b)? undef : a - b;
|
||||||
|
|
||||||
|
|
||||||
|
// Function: u_mul()
|
||||||
|
// Usage:
|
||||||
|
// x = u_mul(a, b);
|
||||||
|
// Description:
|
||||||
|
// Multiplies `a` by `b`, returning the result, or undef if either value is `undef`.
|
||||||
|
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
||||||
|
// Arguments:
|
||||||
|
// a = First value.
|
||||||
|
// b = Second value.
|
||||||
|
function u_mul(a,b) =
|
||||||
|
is_undef(a) || is_undef(b)? undef :
|
||||||
|
is_vector(a) && is_vector(b)? v_mul(a,b) :
|
||||||
|
a * b;
|
||||||
|
|
||||||
|
|
||||||
|
// Function: u_div()
|
||||||
|
// Usage:
|
||||||
|
// x = u_div(a, b);
|
||||||
|
// Description:
|
||||||
|
// Divides `a` by `b`, returning the result, or undef if either value is `undef`.
|
||||||
|
// This emulates the way undefs used to be handled in versions of OpenSCAD before 2020.
|
||||||
|
// Arguments:
|
||||||
|
// a = First value.
|
||||||
|
// b = Second value.
|
||||||
|
function u_div(a,b) =
|
||||||
|
is_undef(a) || is_undef(b)? undef :
|
||||||
|
is_vector(a) && is_vector(b)? v_div(a,b) :
|
||||||
|
a / b;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Section: Boolean list testing
|
||||||
|
|
||||||
|
// Function: any()
|
||||||
|
// Usage:
|
||||||
|
// bool = any(l);
|
||||||
|
// bool = any(l, func); // Requires OpenSCAD 2021.01 or later.
|
||||||
|
// Requirements:
|
||||||
|
// Requires OpenSCAD 2021.01 or later to use the `func=` argument.
|
||||||
|
// Description:
|
||||||
|
// Returns true if any item in list `l` evaluates as true.
|
||||||
|
// Arguments:
|
||||||
|
// l = The list to test for true items.
|
||||||
|
// func = An optional function literal of signature (x), returning bool, to test each list item with.
|
||||||
|
// Example:
|
||||||
|
// any([0,false,undef]); // Returns false.
|
||||||
|
// any([1,false,undef]); // Returns true.
|
||||||
|
// any([1,5,true]); // Returns true.
|
||||||
|
// any([[0,0], [0,0]]); // Returns true.
|
||||||
|
// any([[0,0], [1,0]]); // Returns true.
|
||||||
|
function any(l, func) =
|
||||||
|
assert(is_list(l), "The input is not a list." )
|
||||||
|
assert(func==undef || is_func(func))
|
||||||
|
is_func(func)
|
||||||
|
? _any_func(l, func)
|
||||||
|
: _any_bool(l);
|
||||||
|
|
||||||
|
function _any_func(l, func, i=0, out=false) =
|
||||||
|
i >= len(l) || out? out :
|
||||||
|
_any_func(l, func, i=i+1, out=out || func(l[i]));
|
||||||
|
|
||||||
|
function _any_bool(l, i=0, out=false) =
|
||||||
|
i >= len(l) || out? out :
|
||||||
|
_any_bool(l, i=i+1, out=out || l[i]);
|
||||||
|
|
||||||
|
|
||||||
|
// Function: all()
|
||||||
|
// Usage:
|
||||||
|
// bool = all(l);
|
||||||
|
// bool = all(l, func); // Requires OpenSCAD 2021.01 or later.
|
||||||
|
// Requirements:
|
||||||
|
// Requires OpenSCAD 2021.01 or later to use the `func=` argument.
|
||||||
|
// Description:
|
||||||
|
// Returns true if all items in list `l` evaluate as true. If `func` is given a function liteal
|
||||||
|
// of signature (x), returning bool, then that function literal is evaluated for each list item.
|
||||||
|
// Arguments:
|
||||||
|
// l = The list to test for true items.
|
||||||
|
// func = An optional function literal of signature (x), returning bool, to test each list item with.
|
||||||
|
// Example:
|
||||||
|
// test1 = all([0,false,undef]); // Returns false.
|
||||||
|
// test2 = all([1,false,undef]); // Returns false.
|
||||||
|
// test3 = all([1,5,true]); // Returns true.
|
||||||
|
// test4 = all([[0,0], [0,0]]); // Returns true.
|
||||||
|
// test5 = all([[0,0], [1,0]]); // Returns true.
|
||||||
|
// test6 = all([[1,1], [1,1]]); // Returns true.
|
||||||
|
function all(l, func) =
|
||||||
|
assert(is_list(l), "The input is not a list.")
|
||||||
|
assert(func==undef || is_func(func))
|
||||||
|
is_func(func)
|
||||||
|
? _all_func(l, func)
|
||||||
|
: _all_bool(l);
|
||||||
|
|
||||||
|
function _all_func(l, func, i=0, out=true) =
|
||||||
|
i >= len(l) || !out? out :
|
||||||
|
_all_func(l, func, i=i+1, out=out && func(l[i]));
|
||||||
|
|
||||||
|
function _all_bool(l, i=0, out=true) =
|
||||||
|
i >= len(l) || !out? out :
|
||||||
|
_all_bool(l, i=i+1, out=out && l[i]);
|
||||||
|
|
||||||
|
|
||||||
|
// Function: count_true()
|
||||||
|
// Usage:
|
||||||
|
// seq = count_true(l, [nmax=]);
|
||||||
|
// seq = count_true(l, func, [nmax=]); // Requires OpenSCAD 2021.01 or later.
|
||||||
|
// Requirements:
|
||||||
|
// Requires OpenSCAD 2021.01 or later to use the `func=` argument.
|
||||||
|
// Description:
|
||||||
|
// Returns the number of items in `l` that evaluate as true.
|
||||||
|
// If `l` is a lists of lists, this is applied recursively to each
|
||||||
|
// sublist. Returns the total count of items that evaluate as true
|
||||||
|
// in all recursive sublists.
|
||||||
|
// Arguments:
|
||||||
|
// l = The list to test for true items.
|
||||||
|
// func = An optional function literal of signature (x), returning bool, to test each list item with.
|
||||||
|
// ---
|
||||||
|
// nmax = Max number of true items to count. Default: `undef` (no limit)
|
||||||
|
// Example:
|
||||||
|
// num1 = count_true([0,false,undef]); // Returns 0.
|
||||||
|
// num2 = count_true([1,false,undef]); // Returns 1.
|
||||||
|
// num3 = count_true([1,5,false]); // Returns 2.
|
||||||
|
// num4 = count_true([1,5,true]); // Returns 3.
|
||||||
|
// num5 = count_true([[0,0], [0,0]]); // Returns 2.
|
||||||
|
// num6 = count_true([[0,0], [1,0]]); // Returns 2.
|
||||||
|
// num7 = count_true([[1,1], [1,1]]); // Returns 2.
|
||||||
|
// num8 = count_true([[1,1], [1,1]], nmax=1); // Returns 1.
|
||||||
|
function count_true(l, func, nmax) =
|
||||||
|
assert(is_list(l))
|
||||||
|
assert(func==undef || is_func(func))
|
||||||
|
is_func(func)
|
||||||
|
? _count_true_func(l, func, nmax)
|
||||||
|
: _count_true_bool(l, nmax);
|
||||||
|
|
||||||
|
function _count_true_func(l, func, nmax, i=0, out=0) =
|
||||||
|
i >= len(l) || (nmax!=undef && out>=nmax) ? out :
|
||||||
|
_count_true_func(
|
||||||
|
l, func, nmax, i = i + 1,
|
||||||
|
out = out + (func(l[i])? 1:0)
|
||||||
|
);
|
||||||
|
|
||||||
|
function _count_true_bool(l, nmax, i=0, out=0) =
|
||||||
|
i >= len(l) || (nmax!=undef && out>=nmax) ? out :
|
||||||
|
_count_true_bool(
|
||||||
|
l, nmax, i = i + 1,
|
||||||
|
out = out + (l[i]? 1:0)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Processing Arguments to Functions and Modules
|
// Section: Processing Arguments to Functions and Modules
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue