From 6db39553e1feae1610278a506b2c70860bc71c69 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Mon, 4 Nov 2024 06:17:11 -0500 Subject: [PATCH 1/5] fix nurbs file header --- nurbs.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nurbs.scad b/nurbs.scad index 78e4390..5d14845 100644 --- a/nurbs.scad +++ b/nurbs.scad @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////// -// LibFile: beziers.scad +// LibFile: nurbs.scad // B-Splines and Non-uniform Rational B-Splines (NURBS) are a way to represent smooth curves and smoothly curving // surfaces with a set of control points. The curve or surface is defined by // the control points and a set of "knot" points. The NURBS can be "clamped" in which case the curve passes through From bb77ec5b96606946a9efa1869752a49cc702c062 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Mon, 4 Nov 2024 20:22:21 -0500 Subject: [PATCH 2/5] added hirth spline --- joiners.scad | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/joiners.scad b/joiners.scad index deb7073..4496fdb 100644 --- a/joiners.scad +++ b/joiners.scad @@ -1220,4 +1220,160 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1 +// Section: Splines + +// Module: hirth() +// Usage: +// hirth(n, ir|id=, or|od=, tooth_angle, [cone_angle=], [chamfer=], [base=], [crop=], [anchor=], [spin=], [orient=] +// Description: +// Create a Hirth face spline. The Hirth face spline is a joint that locks together two cylinders using radially +// positioned triangular teeth on the ends of the cylinders. If the joint is held together (e.g. with a screw) then +// the two parts will rotate (or not) together. The two parts of the regular Hirth spline joint are identical. +// Each tooth is a triangle that grows larger with radius. You specify a nominal tooth angle; the actual tooth +// angle will be slightly different. +// . +// You can also specify a cone_angle which raises or lowers the angle of the teeth. When you do this you ened to +// mate splines with opposite angles such as -20 and +20. The splines appear centered at the origin so that two +// splines will mate if their centers coincide. Therefore `attach(CENTER,CENTER)` will produce two mating splines +// assuming that they are rotated correctly. The bottom anchors will be at the bottom of the spline base. The top +// anchors are at an arbitrary location and are not useful. +// . +// By default the spline is created as a polygon with `2n` edges. For large choices of `n` this will produce a nice +// result, but the inner radius will be only approximately the value requested. if you want a cylindrical result with +// exactly accurate radii then set `crop=true`, which will intersect the shape with a suitable cylinder. Note that cropping +// makes the most difference when the tooth count is low. +// . +// The teeth are chamfered proportionally based on the `chamfer` argument which specifies the fraction of the teeth tips +// to remove. The teeth valleys are chamfered by half the specified value to ensure that there is room for the parts +// to mate. The base is added based on the unchamfered dimensions of the joint, and the "teeth_bot" anchor is located +// based on the unchamfered dimensions. +// Named Anchors: +// "teeth_bot" = center of the joint, aligned with the bottom of the (unchamfered) teeth, pointing DOWN. +// "mate" = center of the joint, pointing UP, but with the correct spin so that the part will mate with a compatible parent joint. +// Arguments: +// n = number of teeth +// ir/id = inner radius or diameter +// or/od = outer radius or diameter +// tooth_angle = nominal tooth angle. Default: 60 +// cone_angle = raise or lower the angle of the teeth in the radial direction. Default: 0 +// chamfer = chamfer teeth by this fraction at tips and half this fraction at valleys. Default: 0.05 +// base = add base of this height to the bottom. Default: 1 +// crop = crop to a cylindrical shape. Default: false +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` +// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` +// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP` +// Example: Basic uncropped hirth spline +// hirth(32,20,50, tooth_angle=60,chamfer=.05); +// Example: Raise cone angle +// hirth(32,20,50, tooth_angle=60,cone_angle=30,chamfer=.05); +// Example: Lower cone angle +// hirth(32,20,50, tooth_angle=60,cone_angle=-30,chamfer=.05); +// Example: Only 8 teeth +// hirth(8,20,50, tooth_angle=60,base=10,chamfer=.05); +// Example: Only 8 teeth, cropped +// hirth(8,20,50, tooth_angle=60,base=10,chamfer=.05, crop=true); +// Example: Two identical parts joined together (with 1 unit offset to reveal the joint line). With odd tooth count you can use the CENTER anchor for the child and the teeth line up correctly. +// hirth(27,20,50, tooth_angle=60,base=2,chamfer=.05) +// up(1) attach(CENTER,CENTER) +// hirth(27,20,50, tooth_angle=60,base=2,chamfer=.05); +// Example: Two conical parts joined together, with opposite cone angles for a correct joint. With an even tooth count you must use the "mate" anchor for correct alignment of the teeth. +// hirth(26,20,50, tooth_angle=60,base=2,cone_angle=30,chamfer=.05) +// up(1) attach(CENTER,"mate") +// hirth(26,20,50, tooth_angle=60,base=2,cone_angle=-30, chamfer=.05); + +module hirth(n, ir, or, id, od, tooth_angle=60, cone_angle=0, chamfer=0.05, base=1, crop=false, orient,anchor,spin) +{ + ir = get_radius(r=ir,d=id); + or = get_radius(r=or,d=od); + dummy = assert(all_positive([ir]), "ir/id must be a positive value") + assert(all_positive([or]), "or/od must be a positive value") + assert(ir Date: Mon, 4 Nov 2024 20:30:46 -0500 Subject: [PATCH 3/5] doc tweak --- joiners.scad | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/joiners.scad b/joiners.scad index 4496fdb..0acc998 100644 --- a/joiners.scad +++ b/joiners.scad @@ -1238,10 +1238,10 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1 // assuming that they are rotated correctly. The bottom anchors will be at the bottom of the spline base. The top // anchors are at an arbitrary location and are not useful. // . -// By default the spline is created as a polygon with `2n` edges. For large choices of `n` this will produce a nice -// result, but the inner radius will be only approximately the value requested. if you want a cylindrical result with -// exactly accurate radii then set `crop=true`, which will intersect the shape with a suitable cylinder. Note that cropping -// makes the most difference when the tooth count is low. +// By default the spline is created as a polygon with `2n` edges and the radius is the outer radius to the unchamfered corners. +// For large choices of `n` this will produce result that is close to circular. For small `n` the result will be obviously polygonal. +// If you want a cylindrical result then set `crop=true`, which will intersect an oversized version of the joint with a suitable cylinder. +// Note that cropping makes the most difference when the tooth count is low. // . // The teeth are chamfered proportionally based on the `chamfer` argument which specifies the fraction of the teeth tips // to remove. The teeth valleys are chamfered by half the specified value to ensure that there is room for the parts @@ -1327,8 +1327,12 @@ module hirth(n, ir, or, id, od, tooth_angle=60, cone_angle=0, chamfer=0.05, base // For uncropped case we scale to match user's desired radius exactly real_or = topspan[1].x; + real_ir = topspan[0].x; + scale = crop ? 1 : or/real_or; + echo(scaled_ir=real_ir*scale); + // used to get true bottom at true target radius; has the endpoints of the bottom valley without chamfer/rounding botspan = zrot(-180/n, [ trans_prof(ir_side, [0,1/2,-tooth_height/2]), From c77243667c780785e237f5bd57d001d95ebc3938 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Tue, 5 Nov 2024 19:16:25 -0500 Subject: [PATCH 4/5] revise hirth --- joiners.scad | 135 ++++++++++++++++++++++----------------------------- 1 file changed, 59 insertions(+), 76 deletions(-) diff --git a/joiners.scad b/joiners.scad index 0acc998..6af8c8e 100644 --- a/joiners.scad +++ b/joiners.scad @@ -1224,7 +1224,7 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1 // Module: hirth() // Usage: -// hirth(n, ir|id=, or|od=, tooth_angle, [cone_angle=], [chamfer=], [base=], [crop=], [anchor=], [spin=], [orient=] +// hirth(n, ir|id=, or|od=, tooth_angle, [cone_angle=], [chamfer=], [rounding=], [base=], [crop=], [anchor=], [spin=], [orient=] // Description: // Create a Hirth face spline. The Hirth face spline is a joint that locks together two cylinders using radially // positioned triangular teeth on the ends of the cylinders. If the joint is held together (e.g. with a screw) then @@ -1256,22 +1256,27 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1 // or/od = outer radius or diameter // tooth_angle = nominal tooth angle. Default: 60 // cone_angle = raise or lower the angle of the teeth in the radial direction. Default: 0 -// chamfer = chamfer teeth by this fraction at tips and half this fraction at valleys. Default: 0.05 +// chamfer = chamfer teeth by this fraction at tips and half this fraction at valleys. Default: 0 +// roudning = round the teeth by this fraction at the tips, and half this fraction at valleys. Default: 0 // base = add base of this height to the bottom. Default: 1 // crop = crop to a cylindrical shape. Default: false // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` // orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP` // Example: Basic uncropped hirth spline -// hirth(32,20,50, tooth_angle=60,chamfer=.05); +// hirth(32,20,50); // Example: Raise cone angle -// hirth(32,20,50, tooth_angle=60,cone_angle=30,chamfer=.05); +// hirth(32,20,50,cone_angle=30); // Example: Lower cone angle -// hirth(32,20,50, tooth_angle=60,cone_angle=-30,chamfer=.05); -// Example: Only 8 teeth +// hirth(32,20,50 cone_angle=-30); +// Example: Only 8 teeth, with chamfering // hirth(8,20,50, tooth_angle=60,base=10,chamfer=.05); // Example: Only 8 teeth, cropped // hirth(8,20,50, tooth_angle=60,base=10,chamfer=.05, crop=true); +// Example: Only 8 teeth, with rounding +// hirth(8,20,50, tooth_angle=60,base=10,rounding=.05); +// Example: Only 8 teeth, different tooth angle, cropping with $fn to crop cylinder aligned with teeth +// hirth(8,20,50, tooth_angle=90,base=10,rounding=.05,crop=true,$fn=48); // Example: Two identical parts joined together (with 1 unit offset to reveal the joint line). With odd tooth count you can use the CENTER anchor for the child and the teeth line up correctly. // hirth(27,20,50, tooth_angle=60,base=2,chamfer=.05) // up(1) attach(CENTER,CENTER) @@ -1281,103 +1286,81 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1 // up(1) attach(CENTER,"mate") // hirth(26,20,50, tooth_angle=60,base=2,cone_angle=-30, chamfer=.05); -module hirth(n, ir, or, id, od, tooth_angle=60, cone_angle=0, chamfer=0.05, base=1, crop=false, orient,anchor,spin) +module hirth(n, ir, or, id, od, tooth_angle=60, cone_angle=0, chamfer, rounding, base=1, crop=false, orient,anchor,spin) { ir = get_radius(r=ir,d=id); or = get_radius(r=or,d=od); dummy = assert(all_positive([ir]), "ir/id must be a positive value") - assert(all_positive([or]), "or/od must be a positive value") + assert(all_positive([or]), "or/od must be a positive value") + assert(is_int(n) && n>1, "n must be an integer larger than 1") assert(ir Date: Tue, 5 Nov 2024 19:43:54 -0500 Subject: [PATCH 5/5] example fix, rounding fn fix --- joiners.scad | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/joiners.scad b/joiners.scad index 6af8c8e..bae03d0 100644 --- a/joiners.scad +++ b/joiners.scad @@ -1268,15 +1268,17 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1 // Example: Raise cone angle // hirth(32,20,50,cone_angle=30); // Example: Lower cone angle -// hirth(32,20,50 cone_angle=-30); +// hirth(32,20,50,cone_angle=-30); +// Example: Adding a large base +// hirth(20,20,50,base=20); // Example: Only 8 teeth, with chamfering -// hirth(8,20,50, tooth_angle=60,base=10,chamfer=.05); +// hirth(8,20,50,tooth_angle=60,base=10,chamfer=.1); // Example: Only 8 teeth, cropped -// hirth(8,20,50, tooth_angle=60,base=10,chamfer=.05, crop=true); +// hirth(8,20,50,tooth_angle=60,base=10,chamfer=.1, crop=true); // Example: Only 8 teeth, with rounding -// hirth(8,20,50, tooth_angle=60,base=10,rounding=.05); +// hirth(8,20,50,tooth_angle=60,base=10,rounding=.1); // Example: Only 8 teeth, different tooth angle, cropping with $fn to crop cylinder aligned with teeth -// hirth(8,20,50, tooth_angle=90,base=10,rounding=.05,crop=true,$fn=48); +// hirth(8,20,50,tooth_angle=90,base=10,rounding=.05,crop=true,$fn=48); // Example: Two identical parts joined together (with 1 unit offset to reveal the joint line). With odd tooth count you can use the CENTER anchor for the child and the teeth line up correctly. // hirth(27,20,50, tooth_angle=60,base=2,chamfer=.05) // up(1) attach(CENTER,CENTER) @@ -1325,9 +1327,12 @@ module hirth(n, ir, or, id, od, tooth_angle=60, cone_angle=0, chamfer, rounding, [ -angle*rounding, ridge_angle-vround], [ 0, ridge_angle-vround] ], - rpts = round_corners(profpts, joint=[rounding/2, rounding]*180/n,closed=false,$fn=128) + // Using computed values for the joints lead to round-off error issues + joints = [(profpts[1]-profpts[0]).x, (profpts[3]-profpts[2]).x], + segs = max(16,segs(or*rounding)), + rpts = round_corners(profpts, joint=joints,closed=false,$fn=segs) ) - concat(rpts, reverse(xflip(rpts))); + concat(rpts, reverse(xflip(select(rpts,1,-2)))); // project spherical coordinate point onto cylinder of radius r cyl_proj = function (r,theta_phi) [for(pt=theta_phi)