fillet/rounding_edge_mask consolidation

This commit is contained in:
Adrian Mariano 2024-05-08 20:15:53 -04:00
parent a036802cea
commit 6098942407
3 changed files with 125 additions and 137 deletions

View file

@ -118,9 +118,12 @@ function _inherit_gear_thickness(thickness,dflt=10) =
// right(8.3) back(74) zrot(87-360/30) zrot(10,cp=[pitchpt,0]) stroke(arc(angle=[0,20],r=10.5),endcaps="arrow2",width=.25); // right(8.3) back(74) zrot(87-360/30) zrot(10,cp=[pitchpt,0]) stroke(arc(angle=[0,20],r=10.5),endcaps="arrow2",width=.25);
// back(84) right(13) text("pressure angle",size=2.5); // back(84) right(13) text("pressure angle",size=2.5);
// } // }
// stroke(arc(r=pitch_radius(mod=5,teeth=30),angle=[87,87+12]),width=.4,endcaps="arrow2",color="red");
// color([1,0,0,1]) back(70)right(-13)zrot(4)text("circular pitch", size=2.5);
// Continues: // Continues:
// The size of the teeth can be specified as the circular pitch, the distance along the pitch circle // The size of the teeth can be specified as the *circular pitch*, which is the tooth width, or more precisely,
// from the start of one tooth to the start of the text tooth. The circular pitch can be computed as // the distance along the pitch circle from the start of one tooth to the start of the text tooth.
// The circular pitch can be computed as
// `PI*d/teeth` where `d` is the diameter of the pitch circle and `teeth` is the number of teeth on the gear. // `PI*d/teeth` where `d` is the diameter of the pitch circle and `teeth` is the number of teeth on the gear.
// This simply divides up the pitch circle into the specified number of teeth. However, the customary // This simply divides up the pitch circle into the specified number of teeth. However, the customary
// way to specify metric gears is using the module, ratio of the diameter of the gear to the number of teeth: `m=d/teeth`. // way to specify metric gears is using the module, ratio of the diameter of the gear to the number of teeth: `m=d/teeth`.

View file

@ -173,13 +173,14 @@ module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTE
// Section: Rounding Masks // Section: Rounding Masks
// Module: rounding_edge_mask() // Module: rounding_edge_mask()
// Aliases: fillet()
// Synopsis: Creates a shape to round a 90° edge. // Synopsis: Creates a shape to round a 90° edge.
// SynTags: Geom // SynTags: Geom
// Topics: Masks, Rounding, Shapes (3D) // Topics: Masks, Rounding, Shapes (3D)
// See Also: rounding_angled_edge_mask(), rounding_corner_mask(), rounding_angled_corner_mask(), default_tag(), diff() // See Also: rounding_angled_edge_mask(), rounding_corner_mask(), rounding_angled_corner_mask(), default_tag(), diff()
// Usage: // Usage:
// rounding_edge_mask(l|h=|length=|height=, r|d=, [excess=]) [ATTACHMENTS]; // rounding_edge_mask(l|h=|length=|height=, r|d=, [ang], [excess=]) [ATTACHMENTS];
// rounding_edge_mask(l|h=|length=|height=, r1=|d1=, r2=|d2=, [excess=]) [ATTACHMENTS]; // rounding_edge_mask(l|h=|length=|height=, r1=|d1=, r2=|d2=, [ang=], [excess=]) [ATTACHMENTS];
// Description: // Description:
// Creates a shape that can be used to round a vertical 90° edge. // Creates a shape that can be used to round a vertical 90° edge.
// Difference it from the object to be rounded. The center of the mask // Difference it from the object to be rounded. The center of the mask
@ -187,6 +188,7 @@ module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTE
// Arguments: // Arguments:
// l/h/length/height = Length of mask. // l/h/length/height = Length of mask.
// r = Radius of the rounding. // r = Radius of the rounding.
// ang = Angle between faces for rounding. Default: 90
// --- // ---
// r1 = Bottom radius of rounding. // r1 = Bottom radius of rounding.
// r2 = Top radius of rounding. // r2 = Top radius of rounding.
@ -200,16 +202,37 @@ module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTE
// Side Effects: // Side Effects:
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set. // Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
// Example(VPD=200,VPR=[55,0,120]): // Example(VPD=200,VPR=[55,0,120]):
// rounding_edge_mask(l=50, r=15);
// Example(VPD=200,VPR=[55,0,120]): With different radii at each end
// rounding_edge_mask(l=50, r1=10, r2=25); // rounding_edge_mask(l=50, r1=10, r2=25);
// Example: // Example(VPD=200,VPR=[55,0,120]): Acute angle
// rounding_edge_mask(l=50, r=10, ang=45);
// Example(VPD=200,VPR=[55,0,120]): A large excess
// rounding_edge_mask(l=50, r=15,excess=4);
// Example: Subtracting from a cube
// difference() { // difference() {
// cube(size=100, center=false); // cube(size=100, center=false);
// #rounding_edge_mask(l=100, r=25, orient=UP, anchor=BOTTOM); // #rounding_edge_mask(l=100, r=25, anchor=BOTTOM);
// } // }
// Example: Varying Rounding Radius // Example: Varying Rounding Radius
// difference() { // difference() {
// cube(size=50, center=false); // cube(size=50, center=false);
// #rounding_edge_mask(l=50, r1=25, r2=10, orient=UP, anchor=BOTTOM); // down(1)rounding_edge_mask(l=52, r1=25, r2=10, anchor=BOTTOM);
// }
// Example: Angle not 90 degrees
// difference() {
// pie_slice(ang=70, h=50, d=100, center=true);
// #rounding_edge_mask(h=51, r=20.0, ang=70, $fn=32);
// }
// Example: Varying Rounding Radius
// difference() {
// pie_slice(ang=70, h=50, d=100, center=true);
// #rounding_angled_edge_mask(h=51, r1=10, r2=25, ang=70, $fn=32);
// }
// Example: Rounding a non-right angled edge, with a zero radius at the bottom.
// difference(){
// linear_extrude(height=50)xflip(x=25)right_triangle([50,50]);
// rounding_edge_mask(l=51, ang=45, r1=0, r2=15, anchor=BOT);
// } // }
// Example: Masking by Attachment // Example: Masking by Attachment
// diff() // diff()
@ -224,38 +247,82 @@ module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTE
// rounding_edge_mask(l=p.z, r=25); // rounding_edge_mask(l=p.z, r=25);
// } // }
// } // }
function rounding_edge_mask(l, r, r1, r2, d, d1, d2, excess=0.1, anchor=CENTER, spin=0, orient=UP, h,height,length) = no_function("rounding_edge_mask");
module rounding_edge_mask(l, r, r1, r2, d, d1, d2, excess=0.1, anchor=CENTER, spin=0, orient=UP, h,height,length) function rounding_edge_mask(l, r, ang=90, r1, r2, d, d1, d2, excess=0.1, anchor=CENTER, spin=0, orient=UP, h,height,length) = no_function("rounding_edge_mask");
module rounding_edge_mask(l, r, ang=90, r1, r2, excess=0.01, d1, d2,d,r,length, h, height, anchor=CENTER, spin=0, orient=UP,
_remove_tag=true)
{ {
l = one_defined([l, h, height, length], "l,h,height,length"); length = one_defined([l,length,h,height],"l,length,h,height");
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1); r1 = get_radius(r1=r1, d1=d1,d=d,r=r);
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1); r2 = get_radius(r2=r2, d1=d2,d=d,r=r);
sides = quantup(segs(max(r1,r2)),4); dummy = assert(all_nonnegative([r1,r2]), "radius/diameter value(s) must be nonnegative")
default_tag("remove") { assert(all_positive([length]), "length/l/h/height must be a positive value")
attachable(anchor,spin,orient, size=[2*r1,2*r1,l], size2=[2*r2,2*r2]) { assert(is_finite(ang) && ang>0 && ang<180, "ang must be a number between 0 and 180");
if (r1<r2) { steps = ceil(segs(r)*(180-ang)/360);
zflip() { function make_path(r) =
linear_extrude(height=l, convexity=4, center=true, scale=r1/r2) { let(
difference() { arc = r==0 ? repeat([0,0],steps+1)
translate(-excess*[1,1]) square(r2+excess); : arc(n=steps+1, r=r, corner=[polar_to_xy(r,ang),[0,0],[r,0]]),
translate([r2,r2]) circle(r=r2, $fn=sides); maxx = last(arc).x,
} maxy = arc[0].y,
} cp = [-excess/tan(ang/2),-excess]
} )
} else { [
linear_extrude(height=l, convexity=4, center=true, scale=r2/r1) { [maxx, -excess],
difference() { cp,
translate(-excess*[1,1]) square(r1+excess); arc[0] + polar_to_xy(excess, 90+ang),
translate([r1,r1]) circle(r=r1, $fn=sides); each arc
} ];
} path1 = path3d(make_path(r1),-length/2);
} path2 = path3d(make_path(r2),length/2);
children(); left_normal = cylindrical_to_xyz(1,90+ang,0);
} left_dir = cylindrical_to_xyz(1,ang,0);
} zdir = unit([length, 0,-(r2-r1)/tan(ang/2)]);
cutfact = 1/sin(ang/2)-1;
v=unit(zrot(ang,zdir)+left_normal);
ref = UP - (v*UP)*v;
backleft_spin=-vector_angle(rot(from=UP,to=v,p=BACK),ref);
override = [
[CENTER, [CENTER,UP]],
[TOP, [[0,0,length/2]]],
[BOT, [[0,0,-length/2]]],
[FWD, [[(r1+r2)/tan(ang/2)/4,0,0]]],
[FWD+BOT, [[r1/tan(ang/2)/2,0,-length/2]]],
[FWD+TOP, [[r2/tan(ang/2)/2,0,length/2]]],
[LEFT, [(r1+r2)/tan(ang/2)/4*left_dir, left_normal,ang-180]],
[LEFT+BOT, [down(length/2,r1/tan(ang/2)/2*left_dir), rot(v=left_dir,-45,p=left_normal),ang-180]],
[LEFT+TOP, [up(length/2,r2/tan(ang/2)/2*left_dir), rot(v=left_dir, 45, p=left_normal),ang-180]],
[LEFT+FWD, [CENTER, left_normal+FWD,ang/2-90]],
[LEFT+FWD+TOP, [[0,0,length/2], left_normal+FWD+UP,ang/2-90]],
[LEFT+FWD+BOT, [[0,0,-length/2], left_normal+FWD+DOWN,ang/2-90]],
[RIGHT, [[(r1+r2)/2/tan(ang/2),0,0],zdir]],
[RIGHT+TOP, [[r2/tan(ang/2),0,length/2],zdir+UP]],
[RIGHT+BOT, [[r1/tan(ang/2),0,-length/2],zdir+DOWN]],
[RIGHT+FWD, [[(r1+r2)/2/tan(ang/2),0,0],zdir+FWD]],
[RIGHT+TOP+FWD, [[r2/tan(ang/2),0,length/2],zdir+UP+FWD]],
[RIGHT+BOT+FWD, [[r1/tan(ang/2),0,-length/2],zdir+DOWN+FWD]],
[BACK, [ (r1+r2)/2/tan(ang/2)*left_dir,zrot(ang,zdir),ang+90]],
[BACK+BOT, [ down(length/2,r1/tan(ang/2)*left_dir),zrot(ang,zdir)+DOWN,ang+90]],
[BACK+UP, [ up(length/2,r2/tan(ang/2)*left_dir),zrot(ang,zdir)+UP,ang+90]],
[BACK+LEFT, [ (r1+r2)/2/tan(ang/2)*left_dir,zrot(ang,zdir)+left_normal, backleft_spin]],
[BACK+BOT+LEFT, [ down(length/2,r1/tan(ang/2)*left_dir),zrot(ang,zdir)+left_normal+DOWN,backleft_spin]],
[BACK+UP+LEFT, [ up(length/2,r2/tan(ang/2)*left_dir),zrot(ang,zdir)+left_normal+UP,backleft_spin]],
[BACK+RIGHT, [cylindrical_to_xyz(cutfact*(r1+r2)/2,ang/2,0), zrot(ang/2,zdir),ang/2+90]],
[BACK+RIGHT+TOP, [cylindrical_to_xyz(cutfact*r2,ang/2,length/2), zrot(ang/2,zdir)+UP,ang/2+90]],
[BACK+RIGHT+BOT, [cylindrical_to_xyz(cutfact*r1,ang/2,-length/2), zrot(ang/2,zdir)+DOWN,ang/2+90]],
];
vnf = vnf_vertex_array([path1,path2],caps=true,col_wrap=true);
default_tag("remove", _remove_tag)
attachable(anchor,spin,orient,size=[1,1,length],override=override){
vnf_polyhedron(vnf);
children();
}
} }
// Module: rounding_corner_mask() // Module: rounding_corner_mask()
// Synopsis: Creates a shape to round 90° corners. // Synopsis: Creates a shape to round 90° corners.
// SynTags: Geom // SynTags: Geom
@ -314,79 +381,12 @@ module rounding_corner_mask(r, d, style="octa", excess=0.1, anchor=CENTER, spin=
} }
// Module: rounding_angled_edge_mask()
// Synopsis: Creates a shape to round edges of any angle.
// SynTags: Geom
// Topics: Masks, Rounding
// See Also: rounding_angled_corner_mask(), rounding_edge_mask(), rounding_corner_mask(), default_tag(), diff()
// Usage:
// rounding_angled_edge_mask(h|l=|length=|height=, r|d=, [ang=]) [ATTACHMENTS];
// rounding_angled_edge_mask(h|l=|length=|height=, r1=|d1=, r2=|d2=, [ang=]) [ATTACHMENTS];
// Description:
// Creates a vertical mask that can be used to round the edge where two face meet, at any arbitrary
// angle. Difference it from the object to be rounded. The center of the mask should align exactly
// with the edge to be rounded.
// Arguments:
// h/l/height/length = Height of vertical mask.
// r = Radius of the rounding.
// ---
// r1 = Bottom radius of rounding.
// r2 = Top radius of rounding.
// d = Diameter of the rounding.
// d1 = Bottom diameter of rounding.
// d2 = Top diameter of rounding.
// ang = Angle that the planes meet at. Default: 90
// 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`
// Side Effects:
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
// Example:
// difference() {
// pie_slice(ang=70, h=50, d=100, center=true);
// #rounding_angled_edge_mask(h=51, r=20.0, ang=70, $fn=32);
// }
// Example: Varying Rounding Radius
// difference() {
// pie_slice(ang=70, h=50, d=100, center=true);
// #rounding_angled_edge_mask(h=51, r1=10, r2=25, ang=70, $fn=32);
// }
function rounding_angled_edge_mask(h, r, r1, r2, d, d1, d2, ang=90, anchor=CENTER, spin=0, orient=UP,l,height,length) = no_function("rounding_angled_edge_mask"); function rounding_angled_edge_mask(h, r, r1, r2, d, d1, d2, ang=90, anchor=CENTER, spin=0, orient=UP,l,height,length) = no_function("rounding_angled_edge_mask");
module rounding_angled_edge_mask(h, r, r1, r2, d, d1, d2, ang=90, anchor=CENTER, spin=0, orient=UP,l,height,length) module rounding_angled_edge_mask(h, r, r1, r2, d, d1, d2, ang=90, anchor=CENTER, spin=0, orient=UP,l,height,length)
{ {
function _mask_shape(r) = [ deprecate("angled_edge_mask");
for (i = [0:1:n]) let (a=90+ang+i*sweep/n) [r*cos(a)+x, r*sin(a)+r], rounding_edge_mask(h=h,r=r,r1=r1,r2=r2,d=d,d1=d1,d2=d1,ang=ang,anchor=anchor,spin=spin,orient=orient,l=l,height=height,length=length)
for (i = [0:1:n]) let (a=90+i*sweep/n) [r*cos(a)+x, r*sin(a)-r], children();
[min(-1, r*cos(270-ang)+x-1), r*sin(270-ang)-r],
[min(-1, r*cos(90+ang)+x-1), r*sin(90+ang)+r],
];
h = one_defined([l, h, height, length], "l,h,height,length");
sweep = 180-ang;
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=1);
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=1);
n = ceil(segs(max(r1,r2))*sweep/360);
x = sin(90-(ang/2))/sin(ang/2) * (r1<r2? r2 : r1);
if(r1<r2) {
default_tag("remove") {
attachable(anchor,spin,orient, size=[2*x*r1/r2,2*r1,h], size2=[2*x,2*r2]) {
zflip() {
linear_extrude(height=h, convexity=4, center=true, scale=r1/r2) {
polygon(_mask_shape(r2));
}
}
children();
}
}
} else {
default_tag("remove") {
attachable(anchor,spin,orient, size=[2*x,2*r1,h], size2=[2*x*r2/r1,2*r2]) {
linear_extrude(height=h, convexity=4, center=true, scale=r2/r1) {
polygon(_mask_shape(r1));
}
children();
}
}
}
} }

View file

@ -3279,9 +3279,8 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
// Section: Miscellaneous // Section: Miscellaneous
// Module: fillet() // Module: fillet()
// Aliases: rounding_edge_mask()
// Synopsis: Creates a smooth fillet between two faces. // Synopsis: Creates a smooth fillet between two faces.
// SynTags: Geom, VNF // SynTags: Geom, VNF
// Topics: Shapes (3D), Attachable // Topics: Shapes (3D), Attachable
@ -3290,15 +3289,15 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
// Creates a shape that can be unioned into a concave joint between two faces, to fillet them. // Creates a shape that can be unioned into a concave joint between two faces, to fillet them.
// Center this part along the concave edge to be chamfered and union it in. // Center this part along the concave edge to be chamfered and union it in.
// //
// Usage: Typical // Usage:
// fillet(l, r, [ang], [overlap], ...) [ATTACHMENTS]; // fillet(l|h=|length=|height=, r|d=, [ang=], [excess=]) [ATTACHMENTS];
// fillet(l|length=|h=|height=, d=, [ang=], [overlap=], ...) [ATTACHMENTS]; // fillet(l|h=|length=|height=, r1=|d1=, r2=|d2=, [ang=], [excess=]) [ATTACHMENTS];
// //
// Arguments: // Arguments:
// l / length / h / height = Length of edge to fillet. // l / length / h / height = Length of edge to fillet.
// r = Radius of fillet. // r = Radius of fillet.
// ang = Angle between faces to fillet. // ang = Angle between faces to fillet.
// overlap = Overlap size for unioning with faces. // excess = Overlap size for unioning with faces.
// --- // ---
// d = Diameter of fillet. // d = Diameter of fillet.
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `FRONT+LEFT` // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `FRONT+LEFT`
@ -3330,6 +3329,11 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
// position(BOT+FRONT) // position(BOT+FRONT)
// fillet(l=50, r=10, spin=180, orient=RIGHT); // fillet(l=50, r=10, spin=180, orient=RIGHT);
// } // }
// Example:
// cuboid(50){
// align(TOP,RIGHT,inset=10) fillet(l=50,r=10,orient=FWD);
// align(TOP,RIGHT,inset=20) cuboid([4,50,20],anchor=BOT);
// }
module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, length, h, height, anchor=CENTER, spin=0, orient=UP) module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, length, h, height, anchor=CENTER, spin=0, orient=UP)
{ {
@ -3338,32 +3342,13 @@ module interior_fillet(l=1.0, r, ang=90, overlap=0.01, d, length, h, height, anc
} }
module fillet(l=1.0, r, ang=90, overlap=0.01, d, length, h, height, anchor=CENTER, spin=0, orient=UP) { function fillet(l, r, ang, r1, r2, d, d1, d2, excess=0.1, anchor=CENTER, spin=0, orient=UP, h,height,length) = no_function("fillet");
l = one_defined([l,length,h,height],"l,length,h,height"); module fillet(l, r, ang=90, r1, r2, excess=0.01, d1, d2,d,length, h, height, anchor=CENTER, spin=0, orient=UP)
r = get_radius(r=r, d=d, dflt=1); {
steps = ceil(segs(r)*(180-ang)/360); rounding_edge_mask(l=l, r1=r1, r2=r2, ang=ang, excess=excess, d1=d1, d2=d2,d=d,r=r,length=length, h=h, height=height,
arc = arc(n=steps+1, r=r, corner=[polar_to_xy(r,ang),[0,0],[r,0]]); anchor=anchor, spin=spin, orient=orient, _remove_tag=false)
maxx = last(arc).x; children();
maxy = arc[0].y; }
path = [
[maxx, -overlap],
polar_to_xy(overlap, 180+ang/2),
arc[0] + polar_to_xy(overlap, 90+ang),
each arc
];
override = function (anchor)
anchor.x>=0 && anchor.y>=0 ? undef
:
[[max(0,anchor.x)*maxx, max(0,anchor.y)*maxy, anchor.z*l/2]];
attachable(anchor,spin,orient, size=[2*maxx,2*maxy,l],override=override) {
if (l > 0) {
linear_extrude(height=l, convexity=4, center=true) {
polygon(path);
}
}
children();
}
}
// Function&Module: heightfield() // Function&Module: heightfield()