From 477dd557810ddecae238b7b4c4454866c1430147 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Thu, 11 Nov 2021 18:50:26 -0500 Subject: [PATCH] remove polygon_shift, hide noncollinear_triple modify glued circle to not produce duplicate points --- attachments.scad | 2 -- geometry.scad | 65 +++++++++++++--------------------------- hull.scad | 2 +- lists.scad | 2 +- rounding.scad | 2 +- shapes2d.scad | 25 +++++++++------- skin.scad | 14 ++++----- tests/test_geometry.scad | 22 ++++---------- tests/test_lists.scad | 3 ++ tests/test_shapes2d.scad | 9 +++--- vnf.scad | 4 +-- 11 files changed, 61 insertions(+), 89 deletions(-) diff --git a/attachments.scad b/attachments.scad index ee3b1ff..51ea9ec 100644 --- a/attachments.scad +++ b/attachments.scad @@ -1952,8 +1952,6 @@ module anchor_arrow2d(s=15, color=[0.333,0.333,1], $tags="anchor-arrow") { - - // Module: expose_anchors() // Usage: // expose_anchors(opacity) {child1() show_anchors(); child2() show_anchors(); ...} diff --git a/geometry.scad b/geometry.scad index 107cf03..97ac59d 100644 --- a/geometry.scad +++ b/geometry.scad @@ -153,7 +153,7 @@ function is_collinear(a, b, c, eps=EPSILON) = assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) let( points = is_def(c) ? [a,b,c]: a ) len(points)<3 ? true : - noncollinear_triple(points,error=false,eps=eps) == []; + _noncollinear_triple(points,error=false,eps=eps) == []; // Function: point_line_distance() @@ -429,7 +429,7 @@ function is_coplanar(points, eps=EPSILON) = assert( is_path(points,dim=3) , "Input should be a list of 3D points." ) assert( is_finite(eps) && eps>=0, "The tolerance should be a non-negative value." ) len(points)<=2 ? false - : let( ip = noncollinear_triple(points,error=false,eps=eps) ) + : let( ip = _noncollinear_triple(points,error=false,eps=eps) ) ip == [] ? false : let( plane = plane3pt(points[ip[0]],points[ip[1]],points[ip[2]]) ) _pointlist_greatest_distance(points,plane) < eps; @@ -850,7 +850,7 @@ function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps ) (len(inside)==0 ? undef : _merge_segments(inside, [inside[0]], eps)) : // 3d case - let(indices = noncollinear_triple(poly)) + let(indices = _noncollinear_triple(poly)) indices==[] ? undef : // Polygon is collinear let( plane = plane3pt(poly[indices[0]], poly[indices[1]], poly[indices[2]]), @@ -1384,25 +1384,22 @@ function circle_circle_tangents(c1,r1,c2,r2,d1,d2) = -// Section: Pointlists - - -// Function: noncollinear_triple() -// Usage: -// test = noncollinear_triple(points); -// Topics: Geometry, Noncollinearity -// Description: -// Finds the indices of three non-collinear points from the pointlist `points`. -// It selects two well separated points to define a line and chooses the third point -// to be the point farthest off the line. The points do not necessarily having the -// same winding direction as the polygon so they cannot be used to determine the -// winding direction or the direction of the normal. -// If all points are collinear returns [] when `error=true` or an error otherwise . -// Arguments: -// points = List of input points. -// error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`. -// eps = Tolerance for collinearity test. Default: EPSILON. -function noncollinear_triple(points,error=true,eps=EPSILON) = +/// Internal Function: _noncollinear_triple() +/// Usage: +/// test = _noncollinear_triple(points); +/// Topics: Geometry, Noncollinearity +/// Description: +/// Finds the indices of three non-collinear points from the pointlist `points`. +/// It selects two well separated points to define a line and chooses the third point +/// to be the point farthest off the line. The points do not necessarily having the +/// same winding direction as the polygon so they cannot be used to determine the +/// winding direction or the direction of the normal. +/// If all points are collinear returns [] when `error=true` or an error otherwise . +/// Arguments: +/// points = List of input points. +/// error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`. +/// eps = Tolerance for collinearity test. Default: EPSILON. +function _noncollinear_triple(points,error=true,eps=EPSILON) = assert( is_path(points), "Invalid input points." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) len(points)<3 ? [] : @@ -1953,26 +1950,6 @@ function reverse_polygon(poly) = [ poly[0], for(i=[len(poly)-1:-1:1]) poly[i] ]; - -// Function: polygon_shift() -// Usage: -// newpoly = polygon_shift(poly, i); -// Topics: Geometry, Polygons -// Description: -// Given a polygon `poly`, rotates the point ordering so that the first point in the polygon path is the one at index `i`. -// This is identical to `list_rotate` except that it checks for doubled endpoints and removed them if present. -// Arguments: -// poly = The list of points in the polygon path. -// i = The index of the point to shift to the front of the path. -// Example: -// polygon_shift([[3,4], [8,2], [0,2], [-4,0]], 2); // Returns [[0,2], [-4,0], [3,4], [8,2]] -function polygon_shift(poly, i) = - let(poly=force_path(poly,"poly")) - assert(is_path(poly), "Invalid polygon." ) - list_rotate(cleanup_path(poly), i); - - - // Function: reindex_polygon() // Usage: // newpoly = reindex_polygon(reference, poly); @@ -2021,7 +1998,7 @@ function reindex_polygon(reference, poly, return_error=false) = [for(i=[0:N-1]) norm(reference[i]-fixpoly[(i+k)%N]) ] ]*I, min_ind = min_index(val), - optimal_poly = polygon_shift(fixpoly, min_ind) + optimal_poly = list_rotate(fixpoly, min_ind) ) return_error? [optimal_poly, val[min_ind]] : optimal_poly; @@ -2175,7 +2152,7 @@ function is_polygon_convex(poly,eps=EPSILON) = ? let( size = max([for(p=poly) norm(p-p0)]), tol=pow(size,2)*eps ) assert( size>eps, "The polygon is self-crossing or its points are collinear" ) min(crosses) >=-tol || max(crosses)<=tol - : let( ip = noncollinear_triple(poly,error=false,eps=eps) ) + : let( ip = _noncollinear_triple(poly,error=false,eps=eps) ) assert( ip!=[], "The points are collinear") let( crx = cross(poly[ip[1]]-poly[ip[0]],poly[ip[2]]-poly[ip[1]]), diff --git a/hull.scad b/hull.scad index a2efb7d..f880d44 100644 --- a/hull.scad +++ b/hull.scad @@ -166,7 +166,7 @@ function hull3d_faces(points) = assert(is_path(points,3),"Invalid input to hull3d_faces") len(points) < 3 ? count(len(points)) : let ( // start with a single non-collinear triangle - tri = noncollinear_triple(points, error=false) + tri = _noncollinear_triple(points, error=false) ) tri==[] ? _hull_collinear(points) : let( diff --git a/lists.scad b/lists.scad index ab557e6..cc44c06 100644 --- a/lists.scad +++ b/lists.scad @@ -497,7 +497,7 @@ function reverse(x) = // Topics: List Handling // See Also: select(), reverse() // Description: -// Rotates the contents of a list by `n` positions left. +// Rotates the contents of a list by `n` positions left, so that list[n] becomes the first entry of the list. // If `n` is negative, then the rotation is `abs(n)` positions to the right. // If `list` is a string, then a string is returned with the characters rotates within the string. // Arguments: diff --git a/rounding.scad b/rounding.scad index bb16be0..1e9eb86 100644 --- a/rounding.scad +++ b/rounding.scad @@ -1132,7 +1132,7 @@ function os_mask(mask, out=false, extra,check_valid, quality, offset) = ) assert(len(origin_index)==1,"Cannot find origin in the mask") let( - points = ([for(pt=polygon_shift(mask,origin_index[0])) [xfactor*max(pt.x,0),-max(pt.y,0)]]) + points = ([for(pt=list_rotate(mask,origin_index[0])) [xfactor*max(pt.x,0),-max(pt.y,0)]]) ) os_profile(deduplicate(move(-points[1],p=list_tail(points))), extra,check_valid,quality,offset); diff --git a/shapes2d.scad b/shapes2d.scad index d59c465..6369ac3 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -367,7 +367,7 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false each arc(N=steps, cp=p, r=rounding, start=a+180/n, angle=-360/n) ], maxx_idx = max_index(column(path2,0)), - path3 = polygon_shift(path2,maxx_idx) + path3 = list_rotate(path2,maxx_idx) ) path3 ), path = apply(mat, path4), @@ -1009,7 +1009,7 @@ function teardrop2d(r, ang=45, cap_h, d, anchor=CENTER, spin=0) = ], closed=true ), maxx_idx = max_index(column(path,0)), - path2 = polygon_shift(path,maxx_idx) + path2 = list_rotate(path,maxx_idx) ) reorient(anchor,spin, two_d=true, path=path2, p=path2); @@ -1051,20 +1051,23 @@ function glued_circles(r, spread=10, tangent=30, d, anchor=CENTER, spin=0) = ea1 = 270+tangent, lobearc = ea1-sa1, lobesegs = ceil(segs(r)*lobearc/360), - lobestep = lobearc / lobesegs, sa2 = 270-tangent, ea2 = 270+tangent, subarc = ea2-sa2, arcsegs = ceil(segs(r2)*abs(subarc)/360), - arcstep = subarc / arcsegs, - path = concat( - [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1], - tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2], - [for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1], - tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2] - ), + // In the tangent zero case the inner curves are missing so we need to complete the two + // outer curves. In the other case the inner curves are present and endpoint=false + // prevents point duplication. + path = tangent==0 ? + concat(arc(N=lobesegs+1, r=r, cp=-cp1, angle=[sa1,ea1]), + arc(N=lobesegs+1, r=r, cp=cp1, angle=[sa1+180,ea1+180])) + : + concat(arc(N=lobesegs, r=r, cp=-cp1, angle=[sa1,ea1], endpoint=false), + [for(theta=lerpn(ea2+180,ea2-subarc+180,arcsegs,endpoint=false)) r2*[cos(theta),sin(theta)] - cp2], + arc(N=lobesegs, r=r, cp=cp1, angle=[sa1+180,ea1+180], endpoint=false), + [for(theta=lerpn(ea2,ea2-subarc,arcsegs,endpoint=false)) r2*[cos(theta),sin(theta)] + cp2]), maxx_idx = max_index(column(path,0)), - path2 = reverse_polygon(polygon_shift(path,maxx_idx)) + path2 = reverse_polygon(list_rotate(path,maxx_idx)) ) reorient(anchor,spin, two_d=true, path=path2, extent=true, p=path2); diff --git a/skin.scad b/skin.scad index 04daf88..61e74a2 100644 --- a/skin.scad +++ b/skin.scad @@ -344,7 +344,7 @@ // hex = path3d(hexagon(side=flare*sidelen, align_side=RIGHT, anchor="side0"),height); // pentmate = path3d(pentagon(side=flare*sidelen,align_side=LEFT,anchor="side0"),height); // // Native index would require mapping first and last vertices together, which is not allowed, so shift -// hexmate = polygon_shift( +// hexmate = list_rotate( // path3d(apply(move(pushvec)*rot(angle),hexagon(side=sidelen,align_side=LEFT,anchor="side0"))), // -1); // join_vertex = lerp( @@ -1540,7 +1540,7 @@ function _skin_distance_match(poly1,poly2) = ; i<=len(big) ; - shifted = polygon_shift(big,i), + shifted = list_rotate(big,i), result =_dp_distance_array(small, shifted, abort_thresh = bestcost), bestmap = result[0]