From 5ebf1c80b956d04b79b6b45372948e5267fa27d1 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 11 Aug 2020 14:32:25 +0100 Subject: [PATCH 1/6] Extend scope of transpose Includes an arg to allow transposing in respecto to the secondary "diagonal" --- arrays.scad | 26 +++++++++++++++++++++++--- tests/test_arrays.scad | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/arrays.scad b/arrays.scad index 6124e89..835fd65 100644 --- a/arrays.scad +++ b/arrays.scad @@ -1287,6 +1287,10 @@ function array_dim(v, depth=undef) = // Function: transpose() // Description: Returns the transposition of the given array. +// When reverse=true, the transposition is done in respect to the secondary diagonal, that is: +// . +// reverse(transpose(reverse(arr))) == transpose(arr, reverse=true) +// By default, reverse=false. // Example: // arr = [ // ["a", "b", "c"], @@ -1313,14 +1317,30 @@ function array_dim(v, depth=undef) = // // ["c", "f"], // // ] // Example: +// arr = [ +// ["a", "b", "c"], +// ["d", "e", "f"], +// ["g", "h", "i"] +// ]; +// t = transpose(arr, reverse=true); +// // Returns: +// // [ +// // ["i", "f", "c"], +// // ["h", "e", "b"], +// // ["g", "d", "a"] +// // ] +// Example: // transpose([3,4,5]); // Returns: [3,4,5] -function transpose(arr) = +function transpose(arr, reverse=false) = assert( is_list(arr) && len(arr)>0, "The array is not a vector neither a matrix." ) is_list(arr[0]) ? let( l0 = len(arr[0]) ) assert([for(a=arr) if(!is_list(a) || len(a)!=l0) 1 ]==[], "The array is not a vector neither a matrix." ) - [for (i=[0:1:l0-1]) - [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] + reverse + ? [for (i=[0:1:l0-1]) + [ for (j=[0:1:len(arr)-1]) arr[len(arr)-1-j][l0-1-i] ] ] + : [for (i=[0:1:l0-1]) + [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] : assert( is_vector(arr), "The array is not a vector neither a matrix." ) arr; diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index 64a7fbb..f121266 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -480,6 +480,7 @@ test_array_dim(); module test_transpose() { assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]); assert(transpose([[1,2,3],[4,5,6]]) == [[1,4],[2,5],[3,6]]); + assert(transpose([[1,2,3],[4,5,6]], reverse=true) == [[6,3],[5,2],[4,1]]); assert(transpose([3,4,5]) == [3,4,5]); } test_transpose(); From 1df84f35525ac78c0a65296413bd89b323c50d3d Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 11 Aug 2020 14:33:42 +0100 Subject: [PATCH 2/6] Revert "Extend scope of transpose" This reverts commit 5ebf1c80b956d04b79b6b45372948e5267fa27d1. --- arrays.scad | 26 +++----------------------- tests/test_arrays.scad | 1 - 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/arrays.scad b/arrays.scad index 835fd65..6124e89 100644 --- a/arrays.scad +++ b/arrays.scad @@ -1287,10 +1287,6 @@ function array_dim(v, depth=undef) = // Function: transpose() // Description: Returns the transposition of the given array. -// When reverse=true, the transposition is done in respect to the secondary diagonal, that is: -// . -// reverse(transpose(reverse(arr))) == transpose(arr, reverse=true) -// By default, reverse=false. // Example: // arr = [ // ["a", "b", "c"], @@ -1317,30 +1313,14 @@ function array_dim(v, depth=undef) = // // ["c", "f"], // // ] // Example: -// arr = [ -// ["a", "b", "c"], -// ["d", "e", "f"], -// ["g", "h", "i"] -// ]; -// t = transpose(arr, reverse=true); -// // Returns: -// // [ -// // ["i", "f", "c"], -// // ["h", "e", "b"], -// // ["g", "d", "a"] -// // ] -// Example: // transpose([3,4,5]); // Returns: [3,4,5] -function transpose(arr, reverse=false) = +function transpose(arr) = assert( is_list(arr) && len(arr)>0, "The array is not a vector neither a matrix." ) is_list(arr[0]) ? let( l0 = len(arr[0]) ) assert([for(a=arr) if(!is_list(a) || len(a)!=l0) 1 ]==[], "The array is not a vector neither a matrix." ) - reverse - ? [for (i=[0:1:l0-1]) - [ for (j=[0:1:len(arr)-1]) arr[len(arr)-1-j][l0-1-i] ] ] - : [for (i=[0:1:l0-1]) - [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] + [for (i=[0:1:l0-1]) + [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] : assert( is_vector(arr), "The array is not a vector neither a matrix." ) arr; diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index f121266..64a7fbb 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -480,7 +480,6 @@ test_array_dim(); module test_transpose() { assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]); assert(transpose([[1,2,3],[4,5,6]]) == [[1,4],[2,5],[3,6]]); - assert(transpose([[1,2,3],[4,5,6]], reverse=true) == [[6,3],[5,2],[4,1]]); assert(transpose([3,4,5]) == [3,4,5]); } test_transpose(); From 50b0f170e7f1fbdf9244b9b12055977ea280831b Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 11 Aug 2020 14:55:25 +0100 Subject: [PATCH 3/6] Extend the scope of transpose It allows a transposition in respect to the secondary "diagonal" --- arrays.scad | 26 +++++++++++++++++++++++--- tests/test_arrays.scad | 2 ++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/arrays.scad b/arrays.scad index 6124e89..835fd65 100644 --- a/arrays.scad +++ b/arrays.scad @@ -1287,6 +1287,10 @@ function array_dim(v, depth=undef) = // Function: transpose() // Description: Returns the transposition of the given array. +// When reverse=true, the transposition is done in respect to the secondary diagonal, that is: +// . +// reverse(transpose(reverse(arr))) == transpose(arr, reverse=true) +// By default, reverse=false. // Example: // arr = [ // ["a", "b", "c"], @@ -1313,14 +1317,30 @@ function array_dim(v, depth=undef) = // // ["c", "f"], // // ] // Example: +// arr = [ +// ["a", "b", "c"], +// ["d", "e", "f"], +// ["g", "h", "i"] +// ]; +// t = transpose(arr, reverse=true); +// // Returns: +// // [ +// // ["i", "f", "c"], +// // ["h", "e", "b"], +// // ["g", "d", "a"] +// // ] +// Example: // transpose([3,4,5]); // Returns: [3,4,5] -function transpose(arr) = +function transpose(arr, reverse=false) = assert( is_list(arr) && len(arr)>0, "The array is not a vector neither a matrix." ) is_list(arr[0]) ? let( l0 = len(arr[0]) ) assert([for(a=arr) if(!is_list(a) || len(a)!=l0) 1 ]==[], "The array is not a vector neither a matrix." ) - [for (i=[0:1:l0-1]) - [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] + reverse + ? [for (i=[0:1:l0-1]) + [ for (j=[0:1:len(arr)-1]) arr[len(arr)-1-j][l0-1-i] ] ] + : [for (i=[0:1:l0-1]) + [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] : assert( is_vector(arr), "The array is not a vector neither a matrix." ) arr; diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index 64a7fbb..2f2ff1c 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -476,10 +476,12 @@ module test_array_dim() { } test_array_dim(); +echo(transpose([[1,2,3],[4,5,6]],reverse=true)); module test_transpose() { assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]); assert(transpose([[1,2,3],[4,5,6]]) == [[1,4],[2,5],[3,6]]); + assert(transpose([[1,2,3],[4,5,6]],reverse=true) == [[6,3], [5,2], [4,1]]); assert(transpose([3,4,5]) == [3,4,5]); } test_transpose(); From 0dc8bf6c8fd311b12418aa35905e88261c4f0c31 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 11 Aug 2020 15:15:49 +0100 Subject: [PATCH 4/6] Review is_path and extend the scope of simplify_path and simplify_pat_indexed - introducing is_matrix in is_path makes it more efficient. - simplify is_path and simplify_path_indexed is now able to deal with path of any dimension. --- paths.scad | 55 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/paths.scad b/paths.scad index 7d5f978..93d82fa 100644 --- a/paths.scad +++ b/paths.scad @@ -43,10 +43,12 @@ include // dim = list of allowed dimensions of the vectors in the path. Default: [2,3] // fast = set to true for fast check that only looks at first entry. Default: false function is_path(list, dim=[2,3], fast=false) = - fast? is_list(list) && is_vector(list[0]) : - is_list(list) && is_list(list[0]) && len(list)>1 && - (is_undef(dim) || in_list(len(list[0]), force_list(dim))) && - is_list_of(list, repeat(0,len(list[0]))); + fast + ? is_list(list) && is_vector(list[0]) + : is_matrix(list) + && len(list)>1 + && len(list[0])>0 + && (is_undef(dim) || in_list(len(list[0]), force_list(dim))); // Function: is_closed_path() @@ -105,32 +107,51 @@ function path_subselect(path, s1, u1, s2, u2, closed=false) = // Function: simplify_path() // Description: -// Takes a path and removes unnecessary collinear points. +// Takes a path and removes unnecessary subsequent collinear points. // Usage: // simplify_path(path, [eps]) // Arguments: -// path = A list of 2D path points. +// path = A list of path points of any dimension. // eps = Largest positional variance allowed. Default: `EPSILON` (1-e9) function simplify_path(path, eps=EPSILON) = - len(path)<=2? path : let( - indices = concat([0], [for (i=[1:1:len(path)-2]) if (!collinear_indexed(path, i-1, i, i+1, eps=eps)) i], [len(path)-1]) - ) [for (i = indices) path[i]]; + assert( is_path(path), "Invalid path." ) + assert( is_undef(eps) || (is_finite(eps) && (eps>=0) ), "Invalid tolerance." ) + len(path)<=2 ? path + : let( + indices = [ 0, + for (i=[1:1:len(path)-2]) + if (!collinear(path[i-1],path[i],path[i+1], eps=eps)) i, + len(path)-1 + ] + ) + [for (i = indices) path[i] ]; // Function: simplify_path_indexed() // Description: -// Takes a list of points, and a path as a list of indices into `points`, -// and removes all path points that are unecessarily collinear. +// Takes a list of points, and a list of indices into `points`, +// and removes from the list all indices of subsequent indexed points that are unecessarily collinear. +// Returns the list of the remained indices. // Usage: -// simplify_path_indexed(path, eps) +// simplify_path_indexed(points,indices, eps) // Arguments: // points = A list of points. -// path = A list of indices into `points` that forms a path. +// indices = A list of indices into `points` that forms a path. // eps = Largest angle variance allowed. Default: EPSILON (1-e9) degrees. -function simplify_path_indexed(points, path, eps=EPSILON) = - len(path)<=2? path : let( - indices = concat([0], [for (i=[1:1:len(path)-2]) if (!collinear_indexed(points, path[i-1], path[i], path[i+1], eps=eps)) i], [len(path)-1]) - ) [for (i = indices) path[i]]; +function simplify_path_indexed(points, indices, eps=EPSILON) = + len(indices)<=2? indices + : let( + indices = concat( indices[0], + [for (i=[1:1:len(indices)-2]) + let( + i1 = indices[i-1], + i2 = indices[i], + i3 = indices[i+1] + ) + if (!collinear(points[i1],points[i2],points[i3], eps=eps)) indices[i]], + indices[len(indices)-1] ) + ) + indices; // Function: path_length() From 2e9d87f5841a0921c1e2355b63c2a41da8bc4236 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 11 Aug 2020 15:21:36 +0100 Subject: [PATCH 5/6] explore new scope of transpose in linear_solve and _qr_factor --- math.scad | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/math.scad b/math.scad index e40c1c6..158b1f2 100644 --- a/math.scad +++ b/math.scad @@ -698,9 +698,8 @@ function linear_solve(A,b) = zeros != [] ? [] : mj ? 0 : qr[1][i][j] + qr =_qr_factor(A, Q=ident(m), column=0, m = m, n=n), + Rzero = + let( R = qr[1] ) + [ for(i=[0:m-1]) [ + let( ri = R[i] ) + for(j=[0:n-1]) i>j ? 0 : ri[j] ] - ] + ] ) [qr[0],Rzero]; function _qr_factor(A,Q, column, m, n) = @@ -763,13 +763,12 @@ function back_substitute(R, b, transpose = false) = let(n=len(R)) assert(is_vector(b,n) || is_matrix(b,n),str("R and b are not compatible in back_substitute ",n, len(b))) transpose - ? reverse(_back_substitute([for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], - reverse(b))) + ? reverse(_back_substitute(transpose(R, reverse=true), reverse(b))) : _back_substitute(R,b); function _back_substitute(R, b, x=[]) = - let(n=len(R)) - len(x) == n ? x + let(n=len(R)) + len(x) == n ? x : let(ind = n - len(x) - 1) R[ind][ind] == 0 ? [] : let( From b6085e0cbc24b76de7f4f911325341c75dd77fe6 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 11 Aug 2020 15:36:44 +0100 Subject: [PATCH 6/6] Exclude echo() --- tests/test_arrays.scad | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index 2f2ff1c..8df23a8 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -476,7 +476,6 @@ module test_array_dim() { } test_array_dim(); -echo(transpose([[1,2,3],[4,5,6]],reverse=true)); module test_transpose() { assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]);