From cdb68ad9779b1d6af7ae34b7226b52cadf566cd1 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Sat, 10 Apr 2021 20:14:40 +0100 Subject: [PATCH] Revert "Review of geometry.scad for speed" This reverts commit 49a3a166eb153105c8c667b4b356e3904f88d237. --- arrays.scad | 16 +++--- common.scad | 11 ++-- geometry.scad | 112 +++++++++++++-------------------------- tests/test_geometry.scad | 8 ++- 4 files changed, 52 insertions(+), 95 deletions(-) diff --git a/arrays.scad b/arrays.scad index 604186b..ac97444 100644 --- a/arrays.scad +++ b/arrays.scad @@ -41,7 +41,6 @@ function is_homogeneous(l, depth=10) = [] == [for(i=[1:len(l)-1]) if( ! _same_type(l[i],l0, depth+1) ) 0 ]; function is_homogenous(l, depth=10) = is_homogeneous(l, depth); - function _same_type(a,b, depth) = (depth==0) || @@ -51,7 +50,7 @@ function _same_type(a,b, depth) = (is_string(a) && is_string(b)) || (is_list(a) && is_list(b) && len(a)==len(b) && []==[for(i=idx(a)) if( ! _same_type(a[i],b[i],depth-1) ) 0] ); - + // Function: select() // Topics: List Handling @@ -98,6 +97,7 @@ function select(list, start, end) = // Function: slice() +// Topics: List Handling // Usage: // list = slice(list,s,e); // Description: @@ -476,7 +476,7 @@ function reverse(x) = // l9 = list_rotate([1,2,3,4,5],6); // Returns: [2,3,4,5,1] function list_rotate(list,n=1) = assert(is_list(list)||is_string(list), "Invalid list or string.") - assert(is_int(n), "The rotation number should be integer") + assert(is_finite(n), "Invalid number") let ( ll = len(list), n = ((n % ll) + ll) % ll, @@ -990,7 +990,7 @@ function _sort_vectors(arr, idxlist, _i=0) = _sort_vectors(equal, idxlist, _i+1), _sort_vectors(greater, idxlist, _i ) ); - + // sorting using compare_vals(); returns indexed list when `indexed==true` function _sort_general(arr, idx=undef, indexed=false) = (len(arr)<=1) ? arr : @@ -1332,8 +1332,6 @@ function permutations(l,n=2) = // pairs = zip(a,b); // triples = zip(a,b,c); // quads = zip([LIST1,LIST2,LIST3,LIST4]); -// Topics: List Handling, Iteration -// See Also: zip_long() // Description: // Zips together two or more lists into a single list. For example, if you have two // lists [3,4,5], and [8,7,6], and zip them together, you get [[3,8],[4,7],[5,6]]. @@ -1359,8 +1357,6 @@ function zip(a,b,c) = // pairs = zip_long(a,b); // triples = zip_long(a,b,c); // quads = zip_long([LIST1,LIST2,LIST3,LIST4]); -// Topics: List Handling, Iteration -// See Also: zip() // Description: // Zips together two or more lists into a single list. For example, if you have two // lists [3,4,5], and [8,7,6], and zip them together, you get [[3,8],[4,7],[5,6]]. @@ -1530,6 +1526,7 @@ function subindex(M, idx) = // [[4,2], 91, false], // [6, [3,4], undef]]; // submatrix(A,[0,2],[1,2]); // Returns [[17, "test"], [[3, 4], undef]] + function submatrix(M,idx1,idx2) = [for(i=idx1) [for(j=idx2) M[i][j] ] ]; @@ -1632,6 +1629,7 @@ function block_matrix(M) = assert(badrows==[], "Inconsistent or invalid input") bigM; + // Function: diagonal_matrix() // Usage: // mat = diagonal_matrix(diag, ); @@ -1857,7 +1855,7 @@ function transpose(arr, reverse=false) = // A = matrix to test // eps = epsilon for comparing equality. Default: 1e-12 function is_matrix_symmetric(A,eps=1e-12) = - approx(A,transpose(A), eps); + approx(A,transpose(A)); // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/common.scad b/common.scad index 6d2d44f..e24c744 100644 --- a/common.scad +++ b/common.scad @@ -205,8 +205,7 @@ function is_func(x) = version_num()>20210000 && is_function(x); // Description: // Tests whether input is a list of entries which all have the same list structure // and are filled with finite numerical data. You can optionally specify a required -// list structure with the pattern argument. -// It returns `true` for the empty list regardless the value of the `pattern`. +// list structure with the pattern argument. It returns `true` for the empty list. // Arguments: // list = list to check // pattern = optional pattern required to match @@ -294,7 +293,7 @@ function default(v,dflt=undef) = is_undef(v)? dflt : v; // v = The list whose items are being checked. // recursive = If true, sublists are checked recursively for defined values. The first sublist that has a defined item is returned. // Examples: -// val = first_defined([undef,7,undef,true]); // Returns: 7 +// val = first_defined([undef,7,undef,true]); // Returns: 1 function first_defined(v,recursive=false,_i=0) = _i, ); // Description: // Given a list of 3 or more coplanar 3D points, returns the coefficients of the normalized cartesian equation of a plane, // that is [A,B,C,D] where Ax+By+Cz=D is the equation of the plane where norm([A,B,C])=1. -// If the points in the list are collinear or not coplanar, then `undef` is returned. +// If `fast` is false and the points in the list are collinear or not coplanar, then `undef` is returned. +// if `fast` is true, then the coplanarity test is skipped and a plane passing through 3 non-collinear arbitrary points is returned. // Arguments: // points = The list of points to find the plane of. +// fast = If true, don't verify that all points in the list are coplanar. Default: false // eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) // Example(3D): // xyzpath = rot(45, v=[-0.3,1,0], p=path3d(star(n=6,id=70,d=100), 70)); @@ -947,21 +911,20 @@ function _covariance_evals(points) = // #stroke(xyzpath,closed=true); // cp = centroid(xyzpath); // move(cp) rot(from=UP,to=plane_normal(plane)) anchor_arrow(); -function plane_from_points(points,fast=false, eps=EPSILON) = +function plane_from_points(points, fast=false, eps=EPSILON) = assert( is_path(points,dim=3), "Improper 3d point list." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) - len(points) == 3 - ? let( plane = plane3pt(points[0],points[1],points[2]) ) - plane==[] ? undef : plane - : let( - cov_evals = _covariance_evals(points), - pm = cov_evals[0], - evals = cov_evals[1], - M = cov_evals[2], - evec = _eigenvec_symm_3(M,evals,i=2) ) -// echo(error_points_plane= abs(max(points*evec)-pm*evec), limit=eps) - !fast && abs(max(points*evec)-pm*evec)>eps*evals[0] ? undef : - [ each evec, pm*evec] ; + let( + indices = noncollinear_triple(points,error=false) + ) + indices==[] ? undef : + let( + p1 = points[indices[0]], + p2 = points[indices[1]], + p3 = points[indices[2]], + plane = plane3pt(p1,p2,p3) + ) + fast || points_on_plane(points,plane,eps=eps) ? plane : undef; // Function: plane_from_polygon() @@ -982,16 +945,17 @@ function plane_from_points(points,fast=false, eps=EPSILON) = // #stroke(xyzpath,closed=true); // cp = centroid(xyzpath); // move(cp) rot(from=UP,to=plane_normal(plane)) anchor_arrow(); -function plane_from_polygon(poly, fast=false, eps=EPSILON) = +function plane_from_polygon(poly, fast=false, eps=EPSILON) = assert( is_path(poly,dim=3), "Invalid polygon." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) - len(poly)==3 ? plane3pt(poly[0],poly[1],poly[2]) : - let( triple = sort(noncollinear_triple(poly,error=false)) ) - triple==[] ? [] : - let( plane = plane3pt(poly[triple[0]],poly[triple[1]],poly[triple[2]])) - fast? plane: points_on_plane(poly, plane, eps=eps)? plane: []; - - + let( + poly = deduplicate(poly), + n = polygon_normal(poly), + plane = [n.x, n.y, n.z, n*poly[0]] + ) + fast? plane: coplanar(poly,eps=eps)? plane: []; + + // Function: plane_normal() // Usage: // plane_normal(plane); @@ -1288,11 +1252,9 @@ function coplanar(points, eps=EPSILON) = len(points)<=2 ? false : let( ip = noncollinear_triple(points,error=false,eps=eps) ) ip == [] ? false : - let( - plane = plane3pt(points[ip[0]],points[ip[1]],points[ip[2]]), - normal = point3d(plane), - pt_nrm = points*normal ) - abs(max(max(pt_nrm)-plane[3], -min(pt_nrm)+plane[3])) < eps; + let( plane = plane3pt(points[ip[0]],points[ip[1]],points[ip[2]]), + normal = point3d(plane) ) + max( points*normal ) - plane[3]< eps*norm(normal); // Function: points_on_plane() @@ -1703,11 +1665,11 @@ function noncollinear_triple(points,error=true,eps=EPSILON) = n = (pb-pa)/nrm, distlist = [for(i=[0:len(points)-1]) _dist2line(points[i]-pa, n)] ) - max(distlist)