diff --git a/masks.scad b/masks.scad index b7d7d95..ddb87cb 100644 --- a/masks.scad +++ b/masks.scad @@ -90,18 +90,36 @@ module angle_pie_mask( } +// Creates a shape that can be used to chamfer a 90 degree edge. +// Difference it from the object to be chamfered. The center of +// the mask object should align exactly with the edge to be chamfered. +// l = Height of mask +// chamfer = Size of chamfer +// orient = Orientation of the cylinder. Use the ORIENT_ constants from constants.h. Default: vertical. +// align = Alignment of the cylinder. Use the V_ constants from constants.h. Default: centered. +// Example: +// difference() { +// cube(50); +// #chamfer_mask(l=50.1, chamfer=10.0, orient=ORIENT_X, align=V_RIGHT); +// } +module chamfer_mask(l=1.0, chamfer=1.0, orient=ORIENT_Z, align=V_ZERO) { + cyl(d=chamfer*2, l=l, align=align, orient=orient, $fn=4); +} + + // Creates a shape that can be used to chamfer a 90 degree edge along the Z axis. // Difference it from the object to be chamfered. The center of the mask // object should align exactly with the edge to be chamfered. // l = Height of mask // chamfer = size of chamfer +// align = Alignment of the cylinder. Use the V_ constants from constants.h. Default: centered. // Example: // difference() { // down(5) cube(10); // chamfer_mask_z(l=10.1, chamfer=2.0); // } -module chamfer_mask_z(l=1.0, chamfer=1.0) { - zrot(45) cube(size=[chamfer*sqrt(2.0), chamfer*sqrt(2.0), l], center=true); +module chamfer_mask_z(l=1.0, chamfer=1.0, align=V_ZERO) { + chamfer_mask(l=l, chamfer=chamfer, orient=ORIENT_Z, align=align); } @@ -110,13 +128,14 @@ module chamfer_mask_z(l=1.0, chamfer=1.0) { // object should align exactly with the edge to be chamfered. // l = Height of mask // chamfer = size of chamfer +// align = Alignment of the cylinder. Use the V_ constants from constants.h. Default: centered. // Example: // difference() { // fwd(5) cube(10); // chamfer_mask_y(l=10.1, chamfer=2.0); // } -module chamfer_mask_y(l=1.0, chamfer=1.0) { - xrot(90) chamfer_mask_z(l=l, chamfer=chamfer); +module chamfer_mask_y(l=1.0, chamfer=1.0, align=V_ZERO) { + chamfer_mask(l=l, chamfer=chamfer, orient=ORIENT_Y, align=align); } @@ -125,13 +144,14 @@ module chamfer_mask_y(l=1.0, chamfer=1.0) { // object should align exactly with the edge to be chamfered. // l = Height of mask // chamfer = size of chamfer +// align = Alignment of the cylinder. Use the V_ constants from constants.h. Default: centered. // Example: // difference() { // left(5) cube(10); // chamfer_mask_x(l=10.1, chamfer=2.0); // } -module chamfer_mask_x(l=1.0, chamfer=1.0) { - yrot(90) chamfer_mask_z(l=l, chamfer=chamfer); +module chamfer_mask_x(l=1.0, chamfer=1.0, align=V_ZERO) { + chamfer_mask(l=l, chamfer=chamfer, orient=ORIENT_X, align=align); } @@ -194,28 +214,112 @@ module chamfer(chamfer=1, size=[1,1,1], edges=[[0,0,0,0], [1,1,0,0], [0,0,0,0]]) } -// Create a mask that can be used to bevel/chamfer the end of a cylinder. -// Difference it from the cylinder to be chamferred. The center of the mask object -// should align exactly with the center of the end of the cylinder to be chamferred. +// Create a mask that can be used to bevel/chamfer the end of a cylindrical region. +// Difference it from the end of the region to be chamferred. The center of the mask +// object should align exactly with the center of the end of the cylindrical region +// to be chamferred. // r = Radius of cylinder to chamfer. // d = Diameter of cylinder to chamfer. Use instead of r. // chamfer = Size of the edge chamferred, inset from edge. (Default: 0.25) // ang = Angle of chamfer in degrees from vertical. (Default: 45) // from_end = If true, chamfer size is measured from end of cylinder. If false, chamfer is measured outset from the radius of the cylinder. (Default: false) +// orient = Orientation of the mask. Use the `ORIENT_` constants from `constants.h`. Default: ORIENT_Z. // Example: // $fa=2; $fs=2; // difference() { // cylinder(r=50, h=100, center=true); -// up(50) chamfer_cylinder_mask(r=50, chamfer=10); +// up(50) !chamfer_cylinder_mask(r=50, chamfer=10); // } -module chamfer_cylinder_mask(r=1.0, d=undef, chamfer=0.25, ang=45, from_end=false) +module chamfer_cylinder_mask(r=1.0, d=undef, chamfer=0.25, ang=45, from_end=false, orient=ORIENT_Z) { - h = chamfer * (from_end? 1 : tan(90-ang)); - r = d==undef? r : d/2; - r2 = r - chamfer * (from_end? tan(ang) : 1); - difference() { - cube([2*r+1, 2*r+1, 2*h], center=true); - down(h+0.01) cylinder(r1=r, r2=r2, h=h+0.01, center=false); + r = get_radius(r=r, d=d, dflt=1); + rot(orient) cylinder_mask(l=chamfer*3, r=r, chamfer2=chamfer, chamfang2=ang, from_end=from_end, ends_only=true, align=V_DOWN); +} + + +// If passed children, bevels/chamfers and/or rounds/fillets the ends of the +// cylindrical/conical region specified. If passed no children, creates +// a mask to bevel/chamfer and/or fillet the ends of the cylindrical +// region specified. Difference the mask from the region. The center +// of the mask object should align exactly with the center of the +// cylindrical region to be chamferred. +// l = Length of the cylindrical/conical region. +// r = Radius of cylindrical region to chamfer. +// r1 = Radius of axis-negative end of the region to chamfer. +// r2 = Radius of axis-positive end of the region to chamfer. +// d = Diameter of cylindrical region to chamfer. +// d1 = Diameter of axis-negative end of the region to chamfer. +// d1 = Diameter of axis-positive end of the region to chamfer. +// chamfer = Size of the chamfers/bevels. (Default: 0.25) +// chamfer1 = Size of the chamfers/bevels for the axis-negative end of the region. +// chamfer2 = Size of the chamfers/bevels for the axis-positive end of the region. +// chamfang = Angle of chamfers/bevels in degrees from the length axis of the region. (Default: 45) +// chamfang1 = Angle of chamfer/bevel of the axis-negative end of the region, in degrees from the length axis. +// chamfang2 = Angle of chamfer/bevel of the axis-positive end of the region, in degrees from the length axis. +// fillet = The radius of the fillets on the ends of the region. Default: none. +// fillet1 = The radius of the fillet on the axis-negative end of the region. +// fillet2 = The radius of the fillet on the axis-positive end of the region. +// circum = If true, region will circumscribe the circle of the given radius/diameter. +// from_end = If true, chamfer/bevel size is measured from end of region. If false, chamfer/bevel is measured outset from the radius of the region. (Default: false) +// overage = The extra thickness of the mask. Default: `10`. +// ends_only = If true, only mask the ends and not around the middle of the cylinder. +// orient = Orientation. Use the `ORIENT_` constants from `constants.scad`. Default: `ORIENT_Z`. +// align = Alignment of the region. Use the `V_` constants from `constants.scad`. Default: `V_ZERO`. +// Example: +// $fa=2; $fs=2; +// difference() { +// cylinder(h=100, r1=60, r2=30, center=true); +// cylinder_mask(l=100, r1=60, r2=30, chamfer=10, from_end=true); +// } +// cylinder_mask(l=100, r=50, chamfer1=10, fillet2=10) { +// cube([100,50,100], center=true); +// } +module cylinder_mask( + l, + r=undef, r1=undef, r2=undef, + d=undef, d1=undef, d2=undef, + chamfer=undef, chamfer1=undef, chamfer2=undef, + chamfang=undef, chamfang1=undef, chamfang2=undef, + fillet=undef, fillet1=undef, fillet2=undef, + circum=false, from_end=false, + overage=10, ends_only=false, + orient=ORIENT_Z, align=V_ZERO +) { + r1 = get_radius(r=r, d=d, r1=r1, d1=d1, dflt=1); + r2 = get_radius(r=r, d=d, r1=r2, d1=d2, dflt=1); + sides = segs(max(r1,r2)); + sc = circum? 1/cos(180/sides) : 1; + vang = atan2(l, r1-r2)/2; + ang1 = first_defined([chamfang1, chamfang, vang]); + ang2 = first_defined([chamfang2, chamfang, 90-vang]); + cham1 = first_defined([chamfer1, chamfer, 0]); + cham2 = first_defined([chamfer2, chamfer, 0]); + fil1 = first_defined([fillet1, fillet, 0]); + fil2 = first_defined([fillet2, fillet, 0]); + maxd = max(r1,r2); + if ($children > 0) { + difference() { + children(); + cylinder_mask(l=l, r1=sc*r1, r2=sc*r2, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, fillet1=fil1, fillet2=fil2, orient=orient, from_end=from_end); + } + } else { + orient_and_align([2*r1, 2*r1, l], orient, align) { + difference() { + union() { + chlen1 = cham1 / (from_end? 1 : tan(ang1)); + chlen2 = cham2 / (from_end? 1 : tan(ang2)); + if (!ends_only) { + cylinder(r=maxd+overage, h=l+2*overage, center=true); + } else { + if (cham2>0) up(l/2-chlen2) cylinder(r=maxd+overage, h=chlen2+overage, center=false); + if (cham1>0) down(l/2+overage) cylinder(r=maxd+overage, h=chlen1+overage, center=false); + if (fil2>0) up(l/2-fil2) cylinder(r=maxd+overage, h=fil2+overage, center=false); + if (fil1>0) down(l/2+overage) cylinder(r=maxd+overage, h=fil1+overage, center=false); + } + } + cyl(r1=sc*r1, r2=sc*r2, l=l, chamfer1=cham1, chamfer2=cham2, chamfang1=ang1, chamfang2=ang2, from_end=from_end, fillet1=fil1, fillet2=fil2); + } + } } } @@ -456,26 +560,13 @@ module fillet_corner_mask(r=1.0) // $fa=2; $fs=2; // difference() { // cylinder(r=50, h=100, center=true); -// up(50) !fillet_cylinder_mask(r=50, fillet=10, xtilt=30); +// up(50) fillet_cylinder_mask(r=50, fillet=10, xtilt=30); // } module fillet_cylinder_mask(r=1.0, fillet=0.25, xtilt=0, ytilt=0) { - dhx = 2*r*sin(xtilt); - dhy = 2*r*sin(ytilt); - dh = hypot(dhy, dhx); - down(dh/2) { - skew_xz(za=xtilt) { - skew_yz(za=ytilt) { - down(fillet) { - difference() { - up((dh+2*fillet)/2) { - cube(size=[r*2+10, r*2+10, dh+2*fillet], center=true); - } - torus(or=r, ir=r-2*fillet); - cylinder(r=r-fillet, h=2*fillet, center=true); - } - } - } + skew_xz(za=xtilt) { + skew_yz(za=ytilt) { + cylinder_mask(l=fillet*3, r=r, fillet2=fillet, ends_only=true, align=V_DOWN); } } }