From efb7a4fada26bcbea87bd22c21418bc7a33de3b9 Mon Sep 17 00:00:00 2001 From: Garth Minette <gminette@gmail.com> Date: Mon, 15 Mar 2021 05:10:23 -0700 Subject: [PATCH] Fixes for worm_gear() --- arrays.scad | 11 +++- gears.scad | 4 +- vnf.scad | 182 ++++++++++++++++++++++++++++++++-------------------- 3 files changed, 125 insertions(+), 72 deletions(-) diff --git a/arrays.scad b/arrays.scad index 5af5b7e..7c420b5 100644 --- a/arrays.scad +++ b/arrays.scad @@ -489,12 +489,19 @@ function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) = indices==[]? [] : assert(is_vector(indices), "Indices must be a list of numbers.") let( + ll = len(list), l = len(indices), end = l-(closed?0:1) ) [ for (i = [0:1:l-1]) let( - a = list[indices[i]], - b = list[indices[(i+1)%l]], + idx1 = indices[i], + idx2 = indices[(i+1)%l], + a = assert(idx1>=0,"Bad index.") + assert(idx1<len(list),"Bad index in indices.") + list[idx1], + b = assert(idx2>=0,"Bad index.") + assert(idx2<len(list),"Bad index in indices.") + list[idx2], eq = (a == b)? true : (a*0 != b*0) || (eps==0)? false : is_num(a) || is_vector(a) ? approx(a, b, eps=eps) diff --git a/gears.scad b/gears.scad index da568c9..3e675f8 100644 --- a/gears.scad +++ b/gears.scad @@ -1420,7 +1420,7 @@ function worm_gear( tp = [0,r1,0] - spherical_to_xyz(r2, 90, 90+zang), zang2 = u * helical ) [ - for (i = [0:1:teeth]) each + for (i = [0:1:teeth-1]) each apply( zrot(-i*360/teeth+zang2) * move(tp) * @@ -1435,7 +1435,7 @@ function worm_gear( face_pts = len(tooth_profile), gear_pts = face_pts * teeth, top_faces =[ - for (i=[0:1:teeth-1], j=[0:1:(face_pts/2)-1]) each [ + for (i=[0:1:teeth-1], j=[0:1:(face_pts/2)-2]) each [ [i*face_pts+j, (i+1)*face_pts-j-1, (i+1)*face_pts-j-2], [i*face_pts+j, (i+1)*face_pts-j-2, i*face_pts+j+1] ], diff --git a/vnf.scad b/vnf.scad index 6f5df85..7f57186 100644 --- a/vnf.scad +++ b/vnf.scad @@ -291,26 +291,27 @@ function vnf_vertex_array( cap1 = first_defined([cap1,caps,false]), cap2 = first_defined([cap2,caps,false]), colcnt = cols - (col_wrap?0:1), - rowcnt = rows - (row_wrap?0:1) + rowcnt = rows - (row_wrap?0:1), + verts = [ + each pts, + if (style=="quincunx") ( + for (r = [0:1:rowcnt-1]) ( + for (c = [0:1:colcnt-1]) ( + let( + i1 = ((r+0)%rows)*cols + ((c+0)%cols), + i2 = ((r+1)%rows)*cols + ((c+0)%cols), + i3 = ((r+1)%rows)*cols + ((c+1)%cols), + i4 = ((r+0)%rows)*cols + ((c+1)%cols) + ) mean([pts[i1], pts[i2], pts[i3], pts[i4]]) + ) + ) + ) + ] ) rows<=1 || cols<=1 ? vnf : vnf_merge(cleanup=true, [ vnf, [ - concat( - pts, - style!="quincunx"? [] : [ - for (r = [0:1:rowcnt-1]) ( - for (c = [0:1:colcnt-1]) ( - let( - i1 = ((r+0)%rows)*cols + ((c+0)%cols), - i2 = ((r+1)%rows)*cols + ((c+0)%cols), - i3 = ((r+1)%rows)*cols + ((c+1)%cols), - i4 = ((r+0)%rows)*cols + ((c+1)%cols) - ) mean([pts[i1], pts[i2], pts[i3], pts[i4]]) - ) - ) - ] - ), + verts, concat( [ for (r = [0:1:rowcnt-1]) ( @@ -337,8 +338,9 @@ function vnf_vertex_array( ) fsets[test?0:1] : ( [[i1,i3,i2],[i1,i4,i3]] ), - rfaces = reverse? [for (face=faces) reverse(face)] : faces - ) rfaces + rfaces = reverse? [for (face=faces) reverse(face)] : faces, + ffaces = [for (face=rfaces) if(len(deduplicate_indexed(verts,face,closed=true))>=3) face] + ) faces ) ) ], @@ -618,14 +620,15 @@ function vnf_bend(vnf,r,d,axis="Z") = // Currently checks for these problems: // Type | Color | Code | Message // ------- | -------- | ------------ | --------------------------------- -// WARNING | Yellow | BIG_FACE | Face has more than 3 vertices, and may confuse CGAL -// WARNING | Brown | NULL_FACE | Face has zero area -// ERROR | Cyan | NONPLANAR | Face vertices are not coplanar -// ERROR | Orange | OVRPOP_EDGE | Too many faces attached at edge -// ERROR | Violet | REVERSAL | Faces reverse across edge -// ERROR | Red | T_JUNCTION | Vertex is mid-edge on another Face -// ERROR | Blue | FACE_ISECT | Faces intersect -// ERROR | Magenta | HOLE_EDGE | Edge bounds Hole +// WARNING | Yellow | BIG_FACE | Face has more than 3 vertices, and may confuse CGAL. +// WARNING | Brown | NULL_FACE | Face has zero area. +// ERROR | Cyan | NONPLANAR | Face vertices are not coplanar. +// ERROR | Brown | DUP_FACE | Multiple instances of the same face. +// ERROR | Orange | MULTCONN | Multiply Connected Geometry. Too many faces attached at Edge. +// ERROR | Violet | REVERSAL | Faces reverse across edge. +// ERROR | Red | T_JUNCTION | Vertex is mid-edge on another Face. +// ERROR | Blue | FACE_ISECT | Faces intersect. +// ERROR | Magenta | HOLE_EDGE | Edge bounds Hole. // . // Still to implement: // - Overlapping coplanar faces. @@ -649,7 +652,7 @@ function vnf_bend(vnf,r,d,axis="Z") = // [a, b, e], [a, c, b], [a, d, c], [a, e, d], [b, c, d, e] // ]); // vnf_validate(vnf); -// Example: OVRPOP_EDGE Errors; More Than Two Faces Attached to the Same Edge. This confuses CGAL, and can lead to failed renders. +// Example: MULTCONN Errors; More Than Two Faces Attached to the Same Edge. This confuses CGAL, and can lead to failed renders. // vnf = vnf_triangulate(linear_sweep(union(square(50), square(50,anchor=BACK+RIGHT)), height=50)); // vnf_validate(vnf); // Example: REVERSAL Errors; Faces Reversed Across Edge @@ -700,61 +703,95 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) = for (face=faces, edge=pair(face,true)) edge[0]<edge[1]? edge : [edge[1],edge[0]] ]), + dfaces = [ + for (face=faces) let( + face=deduplicate_indexed(varr,face,closed=true) + ) if(len(face)>=3) + face + ], + face_areas = [ + for (face = faces) + len(face) < 3? 0 : + polygon_area([for (k=face) varr[k]]) + ], edgecnts = unique_count(edges), uniq_edges = edgecnts[0], + issues = [] + ) + let( big_faces = !show_warns? [] : [ for (face = faces) if (len(face) > 3) _vnf_validate_err("BIG_FACE", [for (i=face) varr[i]]) ], null_faces = !show_warns? [] : [ - for (face = faces) let( - face = deduplicate(face,closed=true) - ) - if (len(face)>=3) let( - faceverts = [for (k=face) varr[k]], - area = polygon_area(faceverts) + for (i = idx(faces)) let( + face = faces[i], + area = face_areas[i], + faceverts = [for (k=face) varr[k]] ) if (is_num(area) && abs(area) < EPSILON) _vnf_validate_err("NULL_FACE", faceverts) ], - nonplanars = unique([ - for (face = faces) let( - faceverts = [for (k=face) varr[k]], - area = polygon_area(faceverts) - ) - if (is_num(area) && abs(area) > EPSILON) - if (!coplanar(faceverts)) - _vnf_validate_err("NONPLANAR", faceverts) - ]), - overpop_edges = unique([ - for (i=idx(uniq_edges)) + issues = concat(big_faces, null_faces) + ) + let( + repeated_faces = [ + for (i=idx(dfaces), j=idx(dfaces)) + if (i!=j) let( + face1 = dfaces[i], + face2 = dfaces[j] + ) if (min(face1) == min(face2)) let( + min1 = min_index(face1), + min2 = min_index(face2) + ) if (min1 == min2) let( + sface1 = list_rotate(face1,min1), + sface2 = list_rotate(face2,min2) + ) if (sface1 == sface2) + _vnf_validate_err("DUP_FACE", [for (i=sface1) varr[i]]) + ], + issues = concat(issues, repeated_faces) + ) issues? issues : + let( + multconn_edges = unique([ + for (i = idx(uniq_edges)) if (edgecnts[1][i]>2) - _vnf_validate_err("OVRPOP_EDGE", [for (i=uniq_edges[i]) varr[i]]) + _vnf_validate_err("MULTCONN", [for (i=uniq_edges[i]) varr[i]]) ]), + issues = concat(issues, multconn_edges) + ) issues? issues : + let( reversals = unique([ - for(i = idx(faces), j = idx(faces)) if(i != j) - if(len(deduplicate(faces[i],closed=true))>=3) - if(len(deduplicate(faces[j],closed=true))>=3) + for(i = idx(dfaces), j = idx(dfaces)) if(i != j) for(edge1 = pair(faces[i],true)) for(edge2 = pair(faces[j],true)) if(edge1 == edge2) // Valid adjacent faces will never have the same vertex ordering. - if(_edge_not_reported(edge1, varr, overpop_edges)) + if(_edge_not_reported(edge1, varr, multconn_edges)) _vnf_validate_err("REVERSAL", [for (i=edge1) varr[i]]) ]), + issues = concat(issues, reversals) + ) issues? issues : + let( t_juncts = unique([ - for (v=idx(varr), edge=uniq_edges) - if (v!=edge[0] && v!=edge[1]) let( - a = varr[edge[0]], - b = varr[v], - c = varr[edge[1]] + for (v=idx(varr), edge=uniq_edges) let( + ia = edge[0], + ib = v, + ic = edge[1] ) - if (a != b && b != c && a != c) let( + if (ia!=ib && ib!=ic && ia!=ic) let( + a = varr[ia], + b = varr[ib], + c = varr[ic] + ) + if (!approx(a,b) && !approx(b,c) && !approx(a,c)) let( pt = segment_closest_point([a,c],b) ) - if (pt == b) + if (approx(pt,b)) _vnf_validate_err("T_JUNCTION", [b]) ]), + issues = concat(issues, t_juncts) + ) issues? issues : + let( isect_faces = !check_isects? [] : unique([ for (i = [0:1:len(faces)-2]) for (j = [i+1:1:len(faces)-1]) let( @@ -787,30 +824,39 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) = if (seg[0] != seg[1]) _vnf_validate_err("FACE_ISECT", seg) ]), + issues = concat(issues, isect_faces) + ) issues? issues : + let( hole_edges = unique([ for (i=idx(uniq_edges)) if (edgecnts[1][i]<2) if (_pts_not_reported(uniq_edges[i], varr, t_juncts)) if (_pts_not_reported(uniq_edges[i], varr, isect_faces)) _vnf_validate_err("HOLE_EDGE", [for (i=uniq_edges[i]) varr[i]]) - ]) - ) concat( - big_faces, - null_faces, - nonplanars, - overpop_edges, - reversals, - t_juncts, - isect_faces, - hole_edges - ); + ]), + issues = concat(issues, hole_edges) + ) issues? issues : + let( + nonplanars = unique([ + for (i = idx(faces)) let( + face = faces[i], + area = face_areas[i], + faceverts = [for (k=face) varr[k]] + ) + if (is_num(area) && abs(area) > EPSILON) + if (!coplanar(faceverts)) + _vnf_validate_err("NONPLANAR", faceverts) + ]), + issues = concat(issues, nonplanars) + ) issues; _vnf_validate_errs = [ ["BIG_FACE", "WARNING", "cyan", "Face has more than 3 vertices, and may confuse CGAL"], ["NULL_FACE", "WARNING", "blue", "Face has zero area."], ["NONPLANAR", "ERROR", "yellow", "Face vertices are not coplanar"], - ["OVRPOP_EDGE", "ERROR", "orange", "Too many faces attached at Edge"], + ["DUP_FACE", "ERROR", "brown", "Multiple instances of the same face."], + ["MULTCONN", "ERROR", "orange", "Multiply Connected Geometry. Too many faces attached at Edge"], ["REVERSAL", "ERROR", "violet", "Faces Reverse Across Edge"], ["T_JUNCTION", "ERROR", "magenta", "Vertex is mid-edge on another Face"], ["FACE_ISECT", "ERROR", "brown", "Faces intersect"],