Merge branch 'master' into revarbat_dev

This commit is contained in:
Garth Minette 2021-01-24 23:28:37 -08:00
commit 48de08f89b
5 changed files with 113 additions and 63 deletions

View file

@ -1277,55 +1277,56 @@ function submatrix(M,idx1,idx2) =
[for(i=idx1) [for(j=idx2) M[i][j] ] ];
// Function: zip()
// Usage: Zipping Two Lists
// pairs = zip(v1, v2, <fit>, <fill>);
// for (p = zip(v1, v2, <fit>, <fill>) ...
// Usage: Zipping Three Lists
// triplets = zip(v1, v2, v3, <*fit*>, <*fill*>);
// for (t = zip(v1, v2, v3, <*fit*>, <*fill*>)) ...
// Usage: Zipping N Lists
// zips = zip(LISTS, <*fit*>, <*fill*>);
// for (z = zip(LISTS, <*fit*>, <*fill*>)) ...
// Function: hstack()
// Usage:
// A = hstack(M1, M2)
// A = hstack(M1, M2, M3)
// A = hstack([M1, M2, M3, ...])
// Description:
// Zips together corresponding items from two or more lists. Returns a list of lists,
// where each sublist contains corresponding items from each of the input lists.
// ie: For three lists, `[[A0, B0, C0], [A1, B1, C1], [A2, B2, C2], ...]`
// Constructs a matrix by horizontally "stacking" together compatible matrices or vectors. Vectors are treated as columsn in the stack.
// This command is the inverse of subindex. Note: strings given in vectors are broken apart into lists of characters. Strings given
// in matrices are preserved as strings. If you need to combine vectors of strings use array_group as shown below to convert the
// vector into a column matrix. Also note that vertical stacking can be done directly with concat.
// Arguments:
// v1 = The first list if given with `v1`/`v2`. A list of two or more lists to zipper, without `v1`/`v2`.
// v2 = A second list.
// v2 = A third list.
// ---
// fit = If `fit=="short"`, the zips together up to the length of the shortest list in vecs. If `fit=="long"`, then pads all lists to the length of the longest, using the value in `fill`. If `fit==false`, then requires all lists to be the same length. Default: false.
// fill = The default value to fill in with if one or more lists if short. Default: undef
// M1 = If given with other arguments, the first matrix (or vector) to stack. If given alone, a list of matrices/vectors to stack.
// M2 = Second matrix/vector to stack
// M3 = Third matrix/vector to stack.
// Example:
// v1 = [1,2,3,4];
// M = ident(3);
// v1 = [2,3,4];
// v2 = [5,6,7];
// v3 = [8,9,10,11];
// a = zip(v1,v3); // returns [[1,8], [2,9], [3,10], [4,11]]
// b = zip([v1,v3]); // returns [[1,8], [2,9], [3,10], [4,11]]
// c = zip([v1,v2], fit="short"); // returns [[1,5], [2,6], [3,7]]
// d = zip([v1,v2], fit="long"); // returns [[1,5], [2,6], [3,7], [4,undef]]
// e = zip([v1,v2], fit="long, fill=0); // returns [[1,5], [2,6], [3,7], [4,0]]
// f = zip(v1,v2,v3, fit="long"); // returns [[1,5,8], [2,6,9], [3,7,10], [4,undef,11]]
// g = zip([v1,v2,v3], fit="long"); // returns [[1,5,8], [2,6,9], [3,7,10], [4,undef,11]]
// Example:
// v1 = [[1,2,3], [4,5,6], [7,8,9]];
// v2 = [[20,19,18], [17,16,15], [14,13,12]];
// zip(v1,v2); // Returns [[1,2,3,20,19,18], [4,5,6,17,16,15], [7,8,9,14,13,12]]
function zip(v1, v2, v3, fit=false, fill=undef) =
(v3!=undef)? zip([v1,v2,v3], fit=fit, fill=fill) :
(v2!=undef)? zip([v1,v2], fit=fit, fill=fill) :
assert(in_list(fit, [false, "short", "long"]), "Invalid fit value." )
assert(all([for(v=v1) is_list(v)]), "One of the inputs to zip is not a list")
// v3 = [8,9,10];
// a = hstack(v1,v2); // Returns [[2, 5], [3, 6], [4, 7]]
// b = hstack(v1,v2,v3); // Returns [[2, 5, 8],
// // [3, 6, 9],
// // [4, 7, 10]]
// c = hstack([M,v1,M]); // Returns [[1, 0, 0, 2, 1, 0, 0],
// // [0, 1, 0, 3, 0, 1, 0],
// // [0, 0, 1, 4, 0, 0, 1]]
// d = hstack(subindex(M,0), subindex(M,[1 2])); // Returns M
// strvec = ["one","two"];
// strmat = [["three","four"], ["five","six"]];
// e = hstack(strvec,strvec); // Returns [["o", "n", "e", "o", "n", "e"],
// // ["t", "w", "o", "t", "w", "o"]]
// f = hstack(array_group(strvec,1), array_group(strvec,1));
// // Returns [["one", "one"],
// // ["two", "two"]]
// g = hstack(strmat,strmat); // Returns: [["three", "four", "three", "four"],
// // [ "five", "six", "five", "six"]]
function hstack(M1, M2, M3) =
(M3!=undef)? hstack([M1,M2,M3]) :
(M2!=undef)? hstack([M1,M2]) :
assert(all([for(v=M1) is_list(v)]), "One of the inputs to hstack is not a list")
let(
minlen = list_shortest(v1),
maxlen = list_longest(v1)
minlen = list_shortest(M1),
maxlen = list_longest(M1)
)
assert(fit!=false || minlen==maxlen, "Input vectors to zip must have the same length")
fit == "long"
? [for(i=[0:1:maxlen-1]) [for(v=v1) for(x=(i<len(v)? v[i] : (fill==undef)? [fill] : fill)) x] ]
: [for(i=[0:1:minlen-1]) [for(v=v1) for(x=v[i]) x] ];
assert(minlen==maxlen, "Input vectors to hstack must have the same length")
[for(row=[0:1:minlen-1])
[for(matrix=M1)
each matrix[row]
]
];
// Function: block_matrix()
@ -1335,10 +1336,35 @@ function zip(v1, v2, v3, fit=false, fill=undef) =
// Create a block matrix by supplying a matrix of matrices, which will
// be combined into one unified matrix. Every matrix in one row
// must have the same height, and the combined width of the matrices
// in each row must be equal.
// in each row must be equal. Strings will stay strings.
// Examples:
// A = [[1,2],
// [3,4]];
// B = ident(2);
// C = block_matrix([[A,B],[B,A],[A,B]]);
// // Returns:
// // [[1, 2, 1, 0],
// // [3, 4, 0, 1],
// // [1, 0, 1, 2],
// // [0, 1, 3, 4],
// // [1, 2, 1, 0],
// // [3, 4, 0, 1]]);
// D = block_matrix([[A,B], ident(4)]);
// // Returns:
// // [[1, 2, 1, 0],
// // [3, 4, 0, 1],
// // [1, 0, 0, 0],
// // [0, 1, 0, 0],
// // [0, 0, 1, 0],
// // [0, 0, 0, 1]]);
// E = [["one", "two"], [3,4]];
// F = block_matrix([[A,A]]);
// // Returns:
// // [["one", "two", "one", "two"],
// // [ 3, 4, 3, 4]]
function block_matrix(M) =
let(
bigM = [for(bigrow = M) each zip(bigrow)],
bigM = [for(bigrow = M) each hstack(bigrow)],
len0 = len(bigM[0]),
badrows = [for(row=bigM) if (len(row)!=len0) 1]
)

View file

@ -1227,12 +1227,15 @@ module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=fals
function path_cut(path, dists, closed=false, direction=false) =
let(long_enough = len(path) >= (closed ? 3 : 2))
assert(long_enough,len(path)<2 ? "Two points needed to define a path" : "Closed path must include three points")
!is_list(dists)? path_cut(path, [dists],closed, direction)[0] :
let(cuts = _path_cut(path,dists,closed))
!direction ? cuts : let(
dir = _path_cuts_dir(path, cuts, closed),
normals = _path_cuts_normals(path, cuts, dir, closed)
) zip(cuts, array_group(dir,1), array_group(normals,1));
!is_list(dists)? path_cut(path, [dists],closed, direction)[0]
: let(cuts = _path_cut(path,dists,closed))
!direction
? cuts
: let(
dir = _path_cuts_dir(path, cuts, closed),
normals = _path_cuts_normals(path, cuts, dir, closed)
)
hstack(cuts, array_group(dir,1), array_group(normals,1));
// Main recursive path cut function
function _path_cut(path, dists, closed=false, pind=0, dtotal=0, dind=0, result=[]) =

View file

@ -155,7 +155,7 @@ include <structs.scad>
// $fa=1;
// zigzagx = [-10, 0, 10, 20, 29, 38, 46, 52, 59, 66, 72, 78, 83, 88, 92, 96, 99, 102, 112];
// zigzagy = concat([0], flatten(repeat([-10,10],8)), [-10,0]);
// zig = zip(zigzagx,zigzagy);
// zig = hstack(zigzagx,zigzagy);
// stroke(zig,width=1); // Original shape
// fwd(20) // Smooth size corners with a cut of 4 and curvature parameter 0.6
// stroke(round_corners(zig,cut=4, k=0.6, method="smooth", closed=false),width=1);
@ -190,9 +190,9 @@ include <structs.scad>
// $fn=36;
// square = [[0,0],[1,0],[1,1],[0,1]];
// spiral = flatten(repeat(concat(square,reverse(square)),5)); // Squares repeat 10 times, forward and backward
// squareind = [for(i=[0:9]) each [i,i,i,i]]; // Index of the square for each point
// squareind = [for(i=[0:9]) each [i,i,i,i]]; // Index of the square for each point
// z = list_range(40)*.2+squareind;
// path3d = zip(spiral,z); // 3D spiral
// path3d = hstack(spiral,z); // 3D spiral
// rounding = squareind/20;
// // Setting k=1 means curvature won't be continuous, but curves are as round as possible
// // Try changing the value to see the effect.
@ -772,9 +772,9 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
// rounded_star = round_corners(star, cut=flatten(repeat([.5,0],5)), $fn=24);
// offset_sweep(rounded_star, height=20, bottom=os_circle(r=4), top=os_circle(r=1), steps=15);
// Example: Rounding a star shaped prism with negative radius values
// star = star(5, r=22, ir=13);
// rounded_star = round_corners(star, cut=flatten(repeat([.5,0],5)), $fn=24);
// offset_sweep(rounded_star, height=20, bottom=os_circle(r=-4), top=os_circle(r=-1), steps=15);
star = star(5, r=22, ir=13);
rounded_star = round_corners(star, cut=flatten(repeat([.5,0],5)), $fn=24);
offset_sweep(rounded_star, height=20, bottom=os_circle(r=-4), top=os_circle(r=-1), steps=15);
// Example: Unexpected corners in the result even with `offset="round"` (the default), even with offset_maxstep set small.
// triangle = [[0,0],[10,0],[5,10]];
// offset_sweep(triangle, height=6, bottom = os_circle(r=-2),steps=16,offset_maxstep=0.25);
@ -914,7 +914,7 @@ function _make_offset_polyhedron(path,offsets, offset_type, flip_faces, quality,
offsetind+1, vertexcount+len(path),
vertices=concat(
vertices,
zip(vertices_faces[0],repeat(offsets[offsetind][1],len(vertices_faces[0])))
path3d(vertices_faces[0],offsets[offsetind][1])
),
faces=concat(faces, vertices_faces[1])
)
@ -993,7 +993,7 @@ function offset_sweep(
),
top_start_ind = len(vertices_faces_bot[0]),
initial_vertices_top = zip(path, repeat(middle,len(path))),
initial_vertices_top = path3d(path, middle),
vertices_faces_top = _make_offset_polyhedron(
path, move(p=offsets_top,[0,middle]),
struct_val(top,"offset"), !clockwise,

View file

@ -495,15 +495,36 @@ module test_zip() {
assert(zip([v1,v2],fit="long", fill=0) == [[1,5],[2,6],[3,7],[4,0]]);
assert(zip([v1,v2,v3],fit="long") == [[1,5,8],[2,6,9],[3,7,10],[4,undef,11]]);
}
test_zip();
//test_zip();
module test_hstack() {
M = ident(3);
v1 = [2,3,4];
v2 = [5,6,7];
v3 = [8,9,10];
a = hstack(v1,v2);
b = hstack(v1,v2,v3);
c = hstack([M,v1,M]);
d = hstack(subindex(M,0), subindex(M,[1, 2]));
assert_equal(a,[[2, 5], [3, 6], [4, 7]]);
assert_equal(b,[[2, 5, 8], [3, 6, 9], [4, 7, 10]]);
assert_equal(c,[[1, 0, 0, 2, 1, 0, 0], [0, 1, 0, 3, 0, 1, 0], [0, 0, 1, 4, 0, 0, 1]]);
assert_equal(d,M);
strmat = [["three","four"], ["five","six"]];
assert_equal(hstack(strmat,strmat), [["three", "four", "three", "four"], ["five", "six", "five", "six"]]);
strvec = ["one","two"];
assert_equal(hstack(strvec,strmat),[["o", "n", "e", "three", "four"], ["t", "w", "o", "five", "six"]]);
}
test_hstack();
module test_block_matrix() {
A = [[1,2],[3,4]];
B = ident(2);
assert_equal(block_matrix([[A,B],[B,A],[A,B]]), [[1,2,1,0],[3,4,0,1],[1,0,1,2],[0,1,3,4],[1,2,1,0],[3,4,0,1]]);
assert_equal(block_matrix([[A,B],ident(4)]), [[1,2,1,0],[3,4,0,1],[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]);
text = [["a","b"],["c","d"]];
assert_equal(block_matrix([[text,B]]), [["a","b",1,0],["c","d",0,1]]);
text = [["aa","bb"],["cc","dd"]];
assert_equal(block_matrix([[text,B]]), [["aa","bb",1,0],["cc","dd",0,1]]);
}
test_block_matrix();

View file

@ -6,7 +6,7 @@
//////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,540];
BOSL_VERSION = [2,0,541];
// Section: BOSL Library Version Functions