From dd1396704926332d0d835962e0e57d95113551f5 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Fri, 2 Apr 2021 16:59:29 -0400 Subject: [PATCH] Cleanup of path_resample, add tests for round_corners, fix bezier_curve and arc to always return n points for either endpoint setting. --- beziers.scad | 8 +++++--- paths.scad | 36 +++++++++++++++++++++--------------- rounding.scad | 2 +- shapes2d.scad | 4 ++-- tests/test_shapes2d.scad | 2 +- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/beziers.scad b/beziers.scad index fb49adc..721d8cf 100644 --- a/beziers.scad +++ b/beziers.scad @@ -435,9 +435,11 @@ function bezier_curvature(curve, u) = // bez = [[0,0], [5,15], [40,20], [60,-15], [80,0]]; // move_copies(bezier_curve(bez, 8)) sphere(r=1.5, $fn=12); // trace_bezier(bez, N=len(bez)-1); -function bezier_curve(curve,n,endpoint) = [each bezier_points(curve, [0:1/n:(n-0.5)/n]), - if (endpoint) curve[len(curve)-1] - ]; +function bezier_curve(curve,n,endpoint=true) = + [ + each bezier_points(curve, rangex(endpoint?n-1:n,0,1)), + if (endpoint) last(curve) + ]; // Function: bezier_segment_closest_point() // Usage: diff --git a/paths.scad b/paths.scad index d5ebae7..e7f765c 100644 --- a/paths.scad +++ b/paths.scad @@ -1238,15 +1238,17 @@ module path_extrude(path, convexity=10, clipsize=100) { module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=false) { length = path_length(path,closed); - distances = is_def(sp)? ( - is_def(n) && is_def(spacing)? range(s=sp, step=spacing, n=n) : - is_def(n)? range(s=sp, e=length, n=n) : - range(s=sp, step=spacing, e=length) - ) : is_def(n) && is_undef(spacing)? ( - closed? - let(range=range(s=0,e=length, n=n+1)) list_head(range) : - range(s=0, e=length, n=n) - ) : ( + distances = + is_def(sp)? ( // Start point given + is_def(n) && is_def(spacing)? range(s=sp, step=spacing, n=n) : + is_def(n)? range(s=sp, e=length, n=n) : + range(s=sp, step=spacing, e=length) + ) + : is_def(n) && is_undef(spacing)? ( let(a=echo(n=n)) // N alone given + closed ? rangex(s=0, e=length, n=n) + : range(s=0, e=length, n=n) + ) + : ( // No start point and spacing is given, N maybe given let( n = is_def(n)? n : floor(length/spacing)+(closed?0:1), ptlist = range(s=0,step=spacing,n=n), @@ -1600,13 +1602,17 @@ function resample_path(path, N, spacing, closed=false) = assert(num_defined([N,spacing])==1,"Must define exactly one of N and spacing") assert(is_bool(closed)) let( - length = path_length(path,closed), - N = is_def(N) ? N : round(length/spacing) + (closed?0:1), - spacing = length/(closed?N:N-1), // Note: worried about round-off error, so don't include - distlist = range(closed?N:N-1,step=spacing), // last point when closed=false - cuts = path_cut_points(path, distlist, closed=closed) + length = path_length(path,closed), + // In the open path case decrease N by 1 so that we don't try to get + // path_cut to return the endpoint (which might fail due to rounding) + // Add last point later + N = is_def(N) ? N-(closed?0:1) : round(length/spacing), + distlist = rangex(N,e=length), + cuts = path_cut_points(path, distlist, closed=closed) ) - concat(subindex(cuts,0),closed?[]:[last(path)]); // Then add last point here + [ each subindex(cuts,0), + if (!closed) last(path) // Then add last point here + ]; diff --git a/rounding.scad b/rounding.scad index 315986a..815e220 100644 --- a/rounding.scad +++ b/rounding.scad @@ -346,7 +346,7 @@ function _bezcorner(points, parm) = ] : _smooth_bez_fill(points,parm), N = max(3,$fn>0 ?$fn : ceil(bezier_segment_length(P)/$fs)) ) - bezier_curve(P,N,endpoint=true); + bezier_curve(P,N+1,endpoint=true); function _chamfcorner(points, parm) = let( diff --git a/shapes2d.scad b/shapes2d.scad index 5ba5c2a..e14467e 100644 --- a/shapes2d.scad +++ b/shapes2d.scad @@ -533,7 +533,7 @@ module dashed_stroke(path, dashpat=[3,3], width=1, closed=false) { function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, long=false, cw=false, ccw=false, endpoint=true) = assert(is_bool(endpoint)) !endpoint ? assert(!wedge, "endpoint cannot be false if wedge is true") - list_head(arc(N,r,angle,d,cp,points,width,thickness,start,wedge,long,cw,ccw,true)) : + list_head(arc(N+1,r,angle,d,cp,points,width,thickness,start,wedge,long,cw,ccw,true)) : assert(is_undef(N) || is_integer(N), "Number of points must be an integer") // First try for 2D arc specified by width and thickness is_def(width) && is_def(thickness)? ( @@ -1875,7 +1875,7 @@ function reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) = sa = ca + 180 + (90/N), ea = ca + 180 - (90/N), cp = polar_to_xy(r, ca) - ) each arc(N=ssegs, r=slen, cp=cp, angle=[sa,ea], endpoint=false) + ) each arc(N=ssegs-1, r=slen, cp=cp, angle=[sa,ea], endpoint=false) ], anchors = [ for (i = [0:1:N-1]) let( diff --git a/tests/test_shapes2d.scad b/tests/test_shapes2d.scad index c13a33d..e31f022 100644 --- a/tests/test_shapes2d.scad +++ b/tests/test_shapes2d.scad @@ -40,7 +40,7 @@ test_turtle(); module test_arc() { assert_approx(arc(N=8, d=100, angle=135, cp=[10,10]), [[60,10],[57.1941665154,26.5139530978],[49.0915741234,41.1744900929],[36.6016038258,52.3362099614],[21.1260466978,58.7463956091],[4.40177619483,59.6856104947],[-11.6941869559,55.0484433951],[-25.3553390593,45.3553390593]]); - assert_approx(arc(N=8, d=100, angle=135, cp=[10,10],endpoint=false), [[60,10],[57.1941665154,26.5139530978],[49.0915741234,41.1744900929],[36.6016038258,52.3362099614],[21.1260466978,58.7463956091],[4.40177619483,59.6856104947],[-11.6941869559,55.0484433951]]); + assert_approx(arc(N=8, d=100, angle=135, cp=[10,10],endpoint=false), [[60,10],[57.8470167866,24.5142338627],[51.5734806151,37.778511651],[41.7196642082,48.6505226681],[29.1341716183,56.1939766256],[14.9008570165,59.7592363336],[0.245483899194,59.0392640202],[-13.5698368413,54.0960632174]]); assert_approx(arc(N=8, d=100, angle=[45,225], cp=[10,10]), [[45.3553390593,45.3553390593],[26.5139530978,57.1941665154],[4.40177619483,59.6856104947],[-16.6016038258,52.3362099614],[-32.3362099614,36.6016038258],[-39.6856104947,15.5982238052],[-37.1941665154,-6.51395309776],[-25.3553390593,-25.3553390593]]); assert_approx(arc(N=8, d=100, start=45, angle=135, cp=[10,10]), [[45.3553390593,45.3553390593],[31.6941869559,55.0484433951],[15.5982238052,59.6856104947],[-1.12604669782,58.7463956091],[-16.6016038258,52.3362099614],[-29.0915741234,41.1744900929],[-37.1941665154,26.5139530978],[-40,10]]); assert_approx(arc(N=8, d=100, start=45, angle=-90, cp=[10,10]), [[45.3553390593,45.3553390593],[52.3362099614,36.6016038258],[57.1941665154,26.5139530978],[59.6856104947,15.5982238052],[59.6856104947,4.40177619483],[57.1941665154,-6.51395309776],[52.3362099614,-16.6016038258],[45.3553390593,-25.3553390593]]);