From 1dc7df18fb1738d56496a3aa4681a3feea11deb2 Mon Sep 17 00:00:00 2001 From: Revar Desmera Date: Tue, 26 Mar 2019 23:23:25 -0700 Subject: [PATCH] Added several bezier functions. --- beziers.scad | 239 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 197 insertions(+), 42 deletions(-) diff --git a/beziers.scad b/beziers.scad index 710f27f..9036e32 100644 --- a/beziers.scad +++ b/beziers.scad @@ -64,7 +64,7 @@ use // **Spline Steps**: The number of straight-line segments to split a bezier segment into, to approximate the bezier curve. The more spline steps, the closer the approximation will be to the curve, but the slower it will be to generate. Usually defaults to 16. -// Section: Functions +// Section: Bezier Segment Functions // Function: bez_point() // Usage: @@ -96,36 +96,68 @@ function bez_point(curve,u)= ); -// Function: bezier_polyline() + +// Function: bezier_segment_closest_point() // Usage: -// bezier_polyline(bezier, [splinesteps], [N]) +// bezier_segment_closest_point(bezier,pt) // Description: -// Takes a bezier path and converts it into a polyline. +// Finds the closest part of the given bezier segment to point `pt`. +// The degree of the curve, N, is one less than the number of points in `curve`. +// Returns `u` for the shortest position on the bezier segment to the given point `pt`. // Arguments: -// bezier = A bezier path to approximate. -// splinesteps = Number of straight lines to split each bezier segment into. default=16 -// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3 +// curve = The list of endpoints and control points for this bezier segment. +// pt = The point to find the closest curve point to. +// max_err = The maximum allowed error when approximating the closest approach. // Example(2D): -// bez = [ -// [0,0], [-5,30], -// [20,60], [50,50], [110,30], -// [60,25], [70,0], [80,-25], -// [80,-50], [50,-50] -// ]; -// trace_polyline(bez, size=1, N=3, showpts=true); -// trace_polyline(bezier_polyline(bez, N=3), size=3); -function bezier_polyline(bezier, splinesteps=16, N=3) = concat( - [ - for ( - b = [0 : N : len(bezier)-N-1], - l = [0 : splinesteps-1] - ) let ( - crv = [for (i=[0 : N]) bezier[b+i]], - u = l / splinesteps - ) bez_point(crv, u) - ], - [bez_point([for (i=[-(N+1) : -1]) bezier[len(bezier)+i]], 1.0)] -); +// pt = [40,15]; +// bez = [[0,0], [20,40], [60,-25], [80,0]]; +// u = bezier_segment_closest_point(bez, pt); +// trace_bezier(bez, N=len(bez)-1); +// color("red") translate(pt) sphere(r=1); +// color("blue") translate(bez_point(bez,u)) sphere(r=1); +function bezier_segment_closest_point(curve, pt, max_err=0.01, u=0, end_u=1, step_u=undef, min_dist=undef, min_u=undef) = + let( + step = step_u == undef? (end_u-u)/(len(curve)*2) : step_u, + t_u = min(u, end_u), + dist = norm(bez_point(curve, t_u)-pt), + md = (min_dist==undef || dist(end_u-step/2))? ( + (step= 0.125 || defl > max_deflect)? ( + bezier_segment_length(curve, start_u, mid_u, max_deflect) + + bezier_segment_length(curve, mid_u, end_u, max_deflect) + ) : norm(ep-sp); + // Function: fillet3pts() @@ -169,6 +201,110 @@ function fillet3pts(p0, p1, p2, r, maxerr=0.1, w=0.5, dw=0.25) = let( fillet3pts(p0, p1, p2, r, maxerr=maxerr, w=w-dw, dw=dw/2); + +// Section: Bezier Path Functions + + +// Function: bezier_path_point() +// Usage: +// bezier_path_point(path, seg, u, [N]) +// Description: Returns the coordinates of bezier path segment `seg` at position `u`. +// Arguments: +// path = A bezier path to approximate. +// seg = Segment number along the path. Each segment is N points long. +// u = The proportion of the way along the segment to find the point of. 0<=`u`<=1 +// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3 +function bezier_path_point(path, seg, u, N=3) = bez_point(select(path,seg*N,(seg+1)*N), u); + + + +// Function: bezier_path_closest_point() +// Usage: +// bezier_path_closest_point(bezier,pt) +// Description: +// Finds the closest part of the given bezier path to point `pt`. +// Returns [segnum, u] for the closest position on the bezier path to the given point `pt`. +// Arguments: +// path = A bezier path to approximate. +// pt = The point to find the closest curve point to. +// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3 +// max_err = The maximum allowed error when approximating the closest approach. +// Example(2D): +// pt = [100,0]; +// bez = [[0,0], [20,40], [60,-25], [80,0], [100,25], [140,25], [160,0]]; +// pos = bezier_path_closest_point(bez, pt); +// xy = bezier_path_point(bez,pos[0],pos[1]); +// echo(pos=pos); +// trace_bezier(bez, N=3); +// color("red") translate(pt) sphere(r=1); +// color("blue") translate(xy) sphere(r=1); +function bezier_path_closest_point(path, pt, N=3, max_err=0.01, seg=0, min_seg=undef, min_u=undef, min_dist=undef) = + let(curve = select(path,seg*N,(seg+1)*N)) + (seg*N+1 >= len(path))? ( + let(curve = select(path, min_seg*N, (min_seg+1)*N)) + [min_seg, bezier_segment_closest_point(curve, pt, max_err=max_err)] + ) : ( + let( + curve = select(path,seg*N,(seg+1)*N), + u = bezier_segment_closest_point(curve, pt, max_err=0.05), + dist = norm(bez_point(curve, u)-pt), + mseg = (min_dist==undef || dist