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);
// 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:
// The size of the teeth can be specified as the circular pitch, 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
// The size of the teeth can be specified as the *circular pitch*, which is the tooth width, or more precisely,
// 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.
// 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`.

View file

@ -173,13 +173,14 @@ module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTE
// Section: Rounding Masks
// Module: rounding_edge_mask()
// Aliases: fillet()
// Synopsis: Creates a shape to round a 90° edge.
// SynTags: Geom
// Topics: Masks, Rounding, Shapes (3D)
// See Also: rounding_angled_edge_mask(), rounding_corner_mask(), rounding_angled_corner_mask(), default_tag(), diff()
// Usage:
// rounding_edge_mask(l|h=|length=|height=, r|d=, [excess=]) [ATTACHMENTS];
// rounding_edge_mask(l|h=|length=|height=, r1=|d1=, r2=|d2=, [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=, [ang=], [excess=]) [ATTACHMENTS];
// Description:
// 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
@ -187,6 +188,7 @@ module chamfer_cylinder_mask(r, chamfer, d, ang=45, from_end=false, anchor=CENTE
// Arguments:
// l/h/length/height = Length of mask.
// r = Radius of the rounding.
// ang = Angle between faces for rounding. Default: 90
// ---
// r1 = Bottom 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:
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
// 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);
// 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() {
// 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
// difference() {
// 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
// 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);
// }
// }
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");
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);
sides = quantup(segs(max(r1,r2)),4);
default_tag("remove") {
attachable(anchor,spin,orient, size=[2*r1,2*r1,l], size2=[2*r2,2*r2]) {
if (r1<r2) {
zflip() {
linear_extrude(height=l, convexity=4, center=true, scale=r1/r2) {
difference() {
translate(-excess*[1,1]) square(r2+excess);
translate([r2,r2]) circle(r=r2, $fn=sides);
}
}
}
} else {
linear_extrude(height=l, convexity=4, center=true, scale=r2/r1) {
difference() {
translate(-excess*[1,1]) square(r1+excess);
translate([r1,r1]) circle(r=r1, $fn=sides);
}
}
}
children();
}
}
length = one_defined([l,length,h,height],"l,length,h,height");
r1 = get_radius(r1=r1, d1=d1,d=d,r=r);
r2 = get_radius(r2=r2, d1=d2,d=d,r=r);
dummy = assert(all_nonnegative([r1,r2]), "radius/diameter value(s) must be nonnegative")
assert(all_positive([length]), "length/l/h/height must be a positive value")
assert(is_finite(ang) && ang>0 && ang<180, "ang must be a number between 0 and 180");
steps = ceil(segs(r)*(180-ang)/360);
function make_path(r) =
let(
arc = r==0 ? repeat([0,0],steps+1)
: arc(n=steps+1, r=r, corner=[polar_to_xy(r,ang),[0,0],[r,0]]),
maxx = last(arc).x,
maxy = arc[0].y,
cp = [-excess/tan(ang/2),-excess]
)
[
[maxx, -excess],
cp,
arc[0] + polar_to_xy(excess, 90+ang),
each arc
];
path1 = path3d(make_path(r1),-length/2);
path2 = path3d(make_path(r2),length/2);
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()
// Synopsis: Creates a shape to round 90° corners.
// 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");
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) = [
for (i = [0:1:n]) let (a=90+ang+i*sweep/n) [r*cos(a)+x, r*sin(a)+r],
for (i = [0:1:n]) let (a=90+i*sweep/n) [r*cos(a)+x, r*sin(a)-r],
[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();
}
}
}
deprecate("angled_edge_mask");
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)
children();
}

View file

@ -3279,9 +3279,8 @@ module path_text(path, text, font, size, thickness, lettersize, offset=0, revers
// Section: Miscellaneous
// Module: fillet()
// Aliases: rounding_edge_mask()
// Synopsis: Creates a smooth fillet between two faces.
// SynTags: Geom, VNF
// 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.
// Center this part along the concave edge to be chamfered and union it in.
//
// Usage: Typical
// fillet(l, r, [ang], [overlap], ...) [ATTACHMENTS];
// fillet(l|length=|h=|height=, d=, [ang=], [overlap=], ...) [ATTACHMENTS];
// Usage:
// fillet(l|h=|length=|height=, r|d=, [ang=], [excess=]) [ATTACHMENTS];
// fillet(l|h=|length=|height=, r1=|d1=, r2=|d2=, [ang=], [excess=]) [ATTACHMENTS];
//
// Arguments:
// l / length / h / height = Length of edge to fillet.
// r = Radius of 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.
// 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)
// 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)
{
@ -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) {
l = one_defined([l,length,h,height],"l,length,h,height");
r = get_radius(r=r, d=d, dflt=1);
steps = ceil(segs(r)*(180-ang)/360);
arc = arc(n=steps+1, r=r, corner=[polar_to_xy(r,ang),[0,0],[r,0]]);
maxx = last(arc).x;
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 fillet(l, r, ang, r1, r2, d, d1, d2, excess=0.1, anchor=CENTER, spin=0, orient=UP, h,height,length) = no_function("fillet");
module fillet(l, r, ang=90, r1, r2, excess=0.01, d1, d2,d,length, h, height, anchor=CENTER, spin=0, orient=UP)
{
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,
anchor=anchor, spin=spin, orient=orient, _remove_tag=false)
children();
}
// Function&Module: heightfield()