From b71f1d2295ecfdfc4b58425cc5dbafbe8b5561f3 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Fri, 26 Dec 2025 13:25:38 -0600 Subject: [PATCH] Lib updates. --- lib/metric-machine-screws.scad | 9 +++ lib/mortice-and-tenon.scad | 125 +++++++++++++++++++++++++++++++++ lib/rounded-cube.scad | 75 ++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 lib/metric-machine-screws.scad create mode 100644 lib/mortice-and-tenon.scad create mode 100644 lib/rounded-cube.scad diff --git a/lib/metric-machine-screws.scad b/lib/metric-machine-screws.scad new file mode 100644 index 0000000..365360b --- /dev/null +++ b/lib/metric-machine-screws.scad @@ -0,0 +1,9 @@ +module m3Nut(h = 2.4, clearance = 0, center=false) { + $fn=6; + cylinder(d=6.35 + 2*clearance, h=h, center=center); +} + +module m4Nut(h = 3.2, clearance = 0, center=false) { + $fn=6; + cylinder(d=8.08 + 2*clearance, h=h, center=center); +} diff --git a/lib/mortice-and-tenon.scad b/lib/mortice-and-tenon.scad new file mode 100644 index 0000000..77736dc --- /dev/null +++ b/lib/mortice-and-tenon.scad @@ -0,0 +1,125 @@ +module tenon(dims) { + translate([0, -0.01, 0]) + difference() { + cube([dims[0], dims[1] + 0.01, dims[2]]); + + // chamfers + color("blue") union() { + translate([-0.5, dims[1]*0.95, dims[2]*0.9]) rotate([45, 0, 0]) + translate([0, 0, -dims[2]/2]) cube([dims[0] + 1, 2, 2]); + translate([-0.5, dims[1]*0.95, -dims[2]*0.8]) rotate([45, 0, 0]) + translate([0, 0, -dims[2]/2]) cube([dims[0] + 1, 2, 2]); + translate([-0.4, dims[1]-1, -0.5]) rotate([0, 0, 45]) + cube([2, 2, dims[2] + 1]); + translate([dims[0]+0.4, dims[1]-1, -0.5]) rotate([0, 0, 45]) + cube([2, 2, dims[2] + 1]); + } + } +} + +module morticeBlank(dims, clearance) { + translate([-clearance, -clearance-0.01, -clearance]) + cube([dims[0] + 2 * clearance, dims[1] + 2 * clearance+0.01, dims[2] + 2 * clearance]); +} + + + +module rectDowel(dim = [6, 16, 3]) { + // rectangular dowel + translate([-dim[0]/2, -dim[1]/2, -dim[2]/2]) + cube(dim); +} + +// Create a cube with a mortice cut out of the center for a snap fit tenon. +// The mortice is aligned on the Y-axis: the dimension in X determines the +// width of the piece and mortice, the dimension in Y determines the depth or +// length of the piece, and the dimension in Z determines the height thickness. +// +// The morticeDim dimensions will be enlarged slightly to allow for adequate +// fitment of the tenon based on the clearance (defaults to 0.2). +module morticeWithSnap( + dim = [10, 20, 5], + morticeDim = [6, 8, 3], + snapDepth = 2, + snapHeight = 1, + clearance = 0.3) { + + mDim = [morticeDim[0] + 2*clearance, + morticeDim[1] + clearance, + morticeDim[2] + clearance]; + difference() { + // block + translate([-dim[0]/2, 0, -dim[2]/2]) cube(dim); + + // cutout + translate([-mDim[0]/2, -clearance, -mDim[2]/2]) union() { + cube(mDim); // mortice cutout + + // snap fit cutout + translate([0, morticeDim[1] - snapDepth, morticeDim[2] + clearance - 0.01]) + cube([morticeDim[0] + clearance, + snapDepth + clearance, + snapHeight + clearance + 0.01]); + } + } +} + +// Create a cube with a tenon and cantilevered snap fit on one side. +// The tenon is aligned on the Y-axis: the dimension in X determines the +// width of the piece and tenon, the dimension in Y determines the depth or +// length of the piece, and the dimension in Z determines the height thickness. +module tenonWithSnap( + dim = [10, 20, 5], + tenonDim = [6, 8, 3], + snapDepth = 2, + snapHeight = 1) { + + // block + translate([-dim[0]/2, 0, -dim[2]/2]) cube(dim); + + // tenon + translate([-tenonDim[0]/2, dim[1] - 0.01, -tenonDim[2]/2]) union() { + // main tenon body + tenonFlexArmThickness = min(tenonDim[2] / 2, 1); + color("blue") translate([0, 0, tenonDim[2] - tenonFlexArmThickness]) + cube([tenonDim[0], tenonDim[1], tenonFlexArmThickness]); + + // fillet on front edge of tenon + /* + translate([0, tenonDim[1] / 4 - 0.05, tenonDim[2] / 4 + 0.03]) + difference() { + color("blue") cube([tenonDim[0], tenonDim[1] / 8, tenonDim[2] / 4]); + color("green") translate([tenonDim[0] /2, tenonDim[1]/8 - tenonDim[2]/16, 0]) rotate([0, 90, 0]) + cylinder(r = tenonDim[2] / 4, h = tenonDim[0] + 0.02, center=true); + } + */ + + // 45-degree chamfer on top edges of tenon base (alignment feature) + difference() { + cube([tenonDim[0], tenonDim[1]*0.4, tenonDim[2]]); + translate([-0.01, tenonDim[1]*0.4, -tenonDim[2]/2]) rotate([45, 0, 0]) + cube([tenonDim[0] + 0.02, tenonDim[1] / 4, tenonDim[2] / 2]); + } + + // cantilevered snap fit + translate([0, tenonDim[1] - snapDepth, tenonDim[2] - 0.01]) + difference() { + cube([tenonDim[0], snapDepth, snapHeight + 0.01]); + color("red") union() { + // front-edge chamfer + translate([-0.01, -snapDepth, snapHeight*0.66]) rotate([-10, 0, 0]) + cube([tenonDim[0] + 0.02, snapDepth, snapHeight + 0.01]); + + // back-edge chamfer + translate([-0.01, snapDepth, snapHeight / 8]) rotate([15, 0, 0]) + cube([tenonDim[0] + 0.02, snapDepth, snapHeight + 0.01]); + + // side chamfers + translate([-tenonDim[0]/4, 0, snapHeight*0.66]) rotate([0, 10, 0]) + cube([tenonDim[0] / 4, snapDepth + 0.02, snapHeight]); + translate([tenonDim[0], 0, snapHeight*0.60]) rotate([0, -10, 0]) + cube([tenonDim[0] / 4, snapDepth + 0.02, snapHeight]); + } + } + } +} diff --git a/lib/rounded-cube.scad b/lib/rounded-cube.scad new file mode 100644 index 0000000..fbaab05 --- /dev/null +++ b/lib/rounded-cube.scad @@ -0,0 +1,75 @@ +module roundedCube(dims = [10, 10, 10], cornerRadii = [2, 2, 2]) { + innerDims = [ + dims[0] - cornerRadii[0]*2, + dims[1] - cornerRadii[1]*2, + dims[2] - cornerRadii[2]*2 ]; + + // X-Y + translate(cornerRadii) + scale([cornerRadii[0], cornerRadii[1], 1]) + cylinder(r=1, h = innerDims[2]); + translate([cornerRadii[0], cornerRadii[1] + innerDims[1], cornerRadii[2]]) + scale([cornerRadii[0], cornerRadii[1], 1]) + cylinder(r=1, h = innerDims[2]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1] + innerDims[1], cornerRadii[2]]) + scale([cornerRadii[0], cornerRadii[1], 1]) + cylinder(r=1, h = innerDims[2]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2]]) + scale([cornerRadii[0], cornerRadii[1], 1]) + cylinder(r=1, h = innerDims[2]); + + translate([cornerRadii[0], cornerRadii[1], 0]) cube([innerDims[0], innerDims[1], dims[2]]); + + // X-Z + translate(cornerRadii) + scale([cornerRadii[0], 1, cornerRadii[2]]) + rotate([-90, 0, 0]) cylinder(r=1, h = innerDims[1]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2]]) + scale([cornerRadii[0], 1, cornerRadii[2]]) + rotate([-90, 0, 0]) cylinder(r=1, h = innerDims[1]); + translate([cornerRadii[0], cornerRadii[1], cornerRadii[2] + innerDims[2]]) + scale([cornerRadii[0], 1, cornerRadii[2]]) + rotate([-90, 0, 0]) cylinder(r=1, h = innerDims[1]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2] + innerDims[2]]) + scale([cornerRadii[0], 1, cornerRadii[2]]) + rotate([-90, 0, 0]) cylinder(r=1, h = innerDims[1]); + + translate([cornerRadii[0], 0, cornerRadii[2]]) cube([innerDims[0], dims[1], innerDims[2]]); + + // Y-Z + translate([cornerRadii[0] + innerDims[0], cornerRadii[1] + innerDims[1], cornerRadii[2]]) + scale([1, cornerRadii[1], cornerRadii[2]]) + rotate([-90, 0, 90]) cylinder(r=1, h = innerDims[0]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2]]) + scale([1, cornerRadii[1], cornerRadii[2]]) + rotate([-90, 0, 90]) cylinder(r=1, h = innerDims[0]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1] + innerDims[1], cornerRadii[2] + innerDims[2]]) + scale([1, cornerRadii[1], cornerRadii[2]]) + rotate([-90, 0, 90]) cylinder(r=1, h = innerDims[0]); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2] + innerDims[2]]) + scale([1, cornerRadii[1], cornerRadii[2]]) + rotate([-90, 0, 90]) cylinder(r=1, h = innerDims[0]); + + translate([0, cornerRadii[1], cornerRadii[2]]) cube([dims[0], innerDims[1], innerDims[2]]); + + + // corners + translate(cornerRadii) + scale(cornerRadii) sphere(r=1); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2]]) + scale(cornerRadii) sphere(r=1); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1] + innerDims[1], cornerRadii[2]]) + scale(cornerRadii) sphere(r=1); + translate([cornerRadii[0], cornerRadii[1] + innerDims[1], cornerRadii[2]]) + scale(cornerRadii) sphere(r=1); + + translate([cornerRadii[0], cornerRadii[1], cornerRadii[2] + innerDims[2]]) + scale(cornerRadii) sphere(r=1); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1], cornerRadii[2] + innerDims[2]]) + scale(cornerRadii) sphere(r=1); + translate([cornerRadii[0] + innerDims[0], cornerRadii[1] + innerDims[1], cornerRadii[2] + innerDims[2]]) + scale(cornerRadii) sphere(r=1); + translate([cornerRadii[0], cornerRadii[1] + innerDims[1], cornerRadii[2] + innerDims[2]]) + scale(cornerRadii) sphere(r=1); + +}