diff --git a/functional/2-in-hose-fitting.scad b/functional/2-in-hose-fitting.scad new file mode 100644 index 0000000..9fd3173 --- /dev/null +++ b/functional/2-in-hose-fitting.scad @@ -0,0 +1,75 @@ +$fn=256; + +// all measurements in mm +height = 100; // total +hoseClampWidth = 12; // accomodate 5/16" (8mm) hose clamp width +sectionHeight = 22; // (height - 2 * hoseClampWidth) / 3; +centerHeight = height - 2 * (hoseClampWidth + sectionHeight); + +/* +difference() { + union() { + // main sections + for (i = [-1,1]) { + translate([0, 0, i * (hoseClampWidth + sectionHeight)]) + cylinder(d = 48, h = sectionHeight, center = true); + } + + // hose pipe fitting sections + for (i = [-1,1]) { + translate([0, 0, i * (0.1 + hoseClampWidth + sectionHeight) * 0.5]) + cylinder(d = 44, h = hoseClampWidth + 0.2, center = true); + + translate([0, 0, i * ((sectionHeight + hoseClampWidth) * 0.5) + (hoseClampWidth * 0.5) - 1]) + cylinder(d1 = 44, d2 = 48, h = 2, center = true); + + translate([0, 0, i * ((sectionHeight + hoseClampWidth) * 0.5) + (hoseClampWidth * 0.5) + 1 - hoseClampWidth]) + cylinder(d1 = 48, d2 = 44, h = 2, center = true); + } + + // center section + cylinder(d = 48, h = sectionHeight, center = true); + + // center ring + translate([0, 0, -1.5]) cylinder(d1 = 48, d2 = 52, h = 3, center = true); + translate([0, 0, 1.5]) cylinder(d1 = 52, d2 = 48, h = 3, center = true); + } + + // hollow out + cylinder(d = 36, h = 100.2, center = true); +} +*/ + +difference() { + union() { + // main sections + for (i = [-1,1]) { + translate([0, 0, i * ((centerHeight + sectionHeight) * 0.5 + hoseClampWidth)]) + cylinder(d = 48, h = sectionHeight, center = true); + } + + // hose pipe fitting sections + for (i = [-1,1]) { + translate([0, 0, i * (0.1 + hoseClampWidth + centerHeight) * 0.5]) + cylinder(d = 44, h = hoseClampWidth + 0.2, center = true); + + color("SlateGray") + translate([0, 0, (hoseClampWidth / 2 - 1) + i * ((centerHeight + hoseClampWidth)* 0.5)]) + cylinder(d1 = 44, d2 = 48, h = 2, center = true); + + color("SeaGreen") + translate([0, 0, -(hoseClampWidth / 2 - 1) + i * ((centerHeight + hoseClampWidth)* 0.5)]) + cylinder(d1 = 48, d2 = 44, h = 2, center = true); + } + + // center section + cylinder(d = 48, h = centerHeight, center = true); + + // center ring + translate([0, 0, -1.5]) cylinder(d1 = 48, d2 = 52, h = 3, center = true); + translate([0, 0, 1.5]) cylinder(d1 = 52, d2 = 48, h = 3, center = true); + } + + // hollow out + cylinder(d = 36, h = 100.2, center = true); +} diff --git a/functional/angled-speaker-support.scad b/functional/angled-speaker-support.scad new file mode 100644 index 0000000..b80f49a --- /dev/null +++ b/functional/angled-speaker-support.scad @@ -0,0 +1,289 @@ +include <../lib/joints.scad> +include <../lib/solids.scad> + +// All linear dimensions are in millimeters, all angles in degrees +boardThickness = 4; +supportAngle = 30; +width = 240; +depth = 180; +toeChop = 36; +tenonDims = [boardThickness, boardThickness, 10]; +morticeDims = [boardThickness, boardThickness + 0.2, 10]; + +$fn = 128; + +module triangleCutouts(h, rep = 2, wMul = 1) { + tH = h - 2*boardThickness; + tW = wMul * tH; + tAng = atan(tH / tW); + diagonalThickness = boardThickness / sin(tAng); + + // triangle cutouts, 1st half + cutoutOffset = tW + boardThickness; + translate([cutoutOffset, -0.1, boardThickness]) rotate([0, 0, 90]) prism(boardThickness + 0.2, tW, tH); + + translate([diagonalThickness, 0, 0]) for (i = [0:rep-1]) { + setOffset = i * (2 * tW + 2 * diagonalThickness); + translate([cutoutOffset + setOffset, -0.1, boardThickness]) mirror([1, 0, 0]) rotate([0, 90, 0]) rotate([0, 0, 90]) prism(boardThickness + 0.2, tH, tW); + translate([cutoutOffset + setOffset - 0.1, -0.1, boardThickness]) rotate([0, 90, 0]) rotate([0, 0, 90]) prism(boardThickness + 0.2, tH, tW); + translate([cutoutOffset + setOffset + diagonalThickness, -0.1, boardThickness]) mirror([1, 0, 0]) rotate([0, 0, 90]) prism(boardThickness + 0.2, tW, tH); + translate([cutoutOffset + setOffset + 2*tW + diagonalThickness - 0.1, -0.1, boardThickness]) rotate([0, 0, 90]) prism(boardThickness + 0.2, tW, tH); + + if (i == rep - 1) { + translate([cutoutOffset + setOffset + 2*tW + 2*diagonalThickness, -0.1, boardThickness]) mirror([1, 0, 0]) rotate([0, 90, 0]) rotate([0, 0, 90]) prism(boardThickness + 0.2, tH, tW); + } + } + +} + +module sidePanel(cutWeight = true) { + difference() { + translate([0, -toeChop, 0]) difference() { + cube([boardThickness, depth, 100]); + translate([-0.1, 0, 0]) union() { + rotate([supportAngle, 0, 0]) cube([boardThickness + 0.2, 240, 100]); + rotate([supportAngle, 0, 0]) translate([0, 192, -80]) cube([boardThickness + 0.2, 40, 100]); + translate([0, -0.1, -0.1]) cube([boardThickness + 0.2, toeChop + 0.1, 101]); + translate([boardThickness/2 + 0.1, 90, 75]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 50, center = true); + + // Speed holes + if (cutWeight) { + translate([boardThickness/2 + 0.1, 60, 14]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 10, center = true); + translate([boardThickness/2 + 0.1, 84, 12]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 8, center = true); + translate([boardThickness/2 + 0.1, 104, 14]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 9, center = true); + translate([boardThickness/2 + 0.1, 130, 20]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 14, center = true); + translate([boardThickness/2 + 0.1, 158, 14]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 10, center = true); + translate([boardThickness/2 + 0.1, 156, 42]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 14, center = true); + translate([boardThickness/2 + 0.1, 158, 70]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 9, center = true); + } + } + } + + // dovetail sockets + + // back panel dovetail socket + translate([boardThickness, -0.01, 10 + 4]) + rotate([-90, 90, 0]) + color("blue") dovetail(tailHeight = boardThickness + 0.01, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness + 0.01); + + // front panel dovetail sockets + translate([boardThickness, 144 - boardThickness, 10 + 12]) + rotate([-90, 90, 0]) + color("blue") dovetail(tailHeight = boardThickness + 0.01, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness + 0.01); + + translate([boardThickness, 144 - boardThickness, 10 + 48]) + rotate([-90, 90, 0]) + color("blue") dovetail(tailHeight = boardThickness + 0.01, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness + 0.01); + + // top panel dovetail sockets + color("blue") + translate([0, -toeChop, 0]) + rotate([supportAngle, 0, 0]) + union() { + translate([boardThickness, toeChop + 16, -boardThickness]) + rotate([0, 0, 90]) + dovetail(tailHeight = boardThickness + 0.01, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness + 0.01); + + translate([boardThickness, toeChop + 138, -boardThickness]) + rotate([0, 0, 90]) + dovetail(tailHeight = boardThickness + 0.01, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness + 0.01); + } + + } +} + +module midPanel(cutWeight = true) { + // main panel + translate([0, -toeChop, 0]) + difference() { + + cube([boardThickness, depth - boardThickness, 100]); + + translate([-0.1, 0, 0]) + union() { + // main cut establishing the angled plane + rotate([supportAngle, 0, 0]) + translate([0, 0, -boardThickness]) + cube([boardThickness + 0.2, 240, 100]); + + // cut off the top corner + rotate([supportAngle, 0, 0]) + translate([0, 192, -80]) + cube([boardThickness + 0.2, 40, 100]); + + // cut off the toe + translate([0, -0.1, -0.1]) + cube([boardThickness + 0.2, toeChop + boardThickness + 0.1, 101]); + + // cut out the main scoop + translate([boardThickness/2 + 0.1, 90, 75]) + rotate([0, 90, 0]) + cylinder(h = boardThickness + 0.2, r = 50, center = true); + + // cut speed holes + if (cutWeight) { + translate([boardThickness/2 + 0.1, 60, 14]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 10, center = true); + translate([boardThickness/2 + 0.1, 84, 12]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 8, center = true); + translate([boardThickness/2 + 0.1, 104, 14]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 9, center = true); + translate([boardThickness/2 + 0.1, 130, 20]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 14, center = true); + translate([boardThickness/2 + 0.1, 158, 14]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 10, center = true); + translate([boardThickness/2 + 0.1, 156, 42]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 14, center = true); + translate([boardThickness/2 + 0.1, 158, 70]) rotate([0, 90, 0]) cylinder(h = boardThickness + 0.2, r = 9, center = true); + } + } + } + + // top panel tenons + translate([0, -toeChop, 0]) // adjust for the toe chop + rotate([supportAngle, 0, 0]) // rotate the tenon plane to match the panel angle + union() { + // lower tenon + // orient the tenon along the plane of the edge + // 10 = bring tenon to origin + // 43.9 = distance on the plane of the top to lip of the piece + // 8 = offset to center the tenon on the piece + translate([0, 10 + 43.9 + 8, -boardThickness]) + rotate([90, 0, 0]) // orient the tenon upright (facing positive Z) + tenon(tenonDims); + + // upper tenon + // orient the tenon along the plane of the edge + // 10 = bring tenon to origin + // 159.3 = distance on the plane of the top to lip of the piece + // 14.7 = offset to place the tenon on the piece + translate([0, 10 + 159.3 + 14.7, -boardThickness]) // orient the tenon along the plane of the edge + rotate([90, 0, 0]) // orient the tenon upright + tenon(tenonDims); + } + + // front panel tenon + translate([0, boardThickness, 4]) + mirror([0, 1, 0]) + tenon(tenonDims); + + // back panel tenons + translate([0, 144 - boardThickness, 8]) tenon(tenonDims); + translate([0, 144 - boardThickness, 48]) tenon(tenonDims); +} + +module backPanel(cutWeight = true) { + panelHeight = 18.4; + translate([boardThickness, 0, 0]) + difference() { + cube([width - boardThickness * 2, boardThickness, panelHeight]); + + if (cutWeight) { + triangleCutouts(h = panelHeight, rep = 3, wMul = 0.95); + translate([width - boardThickness * 2, 0, 0]) mirror([1, 0, 0]) triangleCutouts(h = panelHeight, rep = 3, wMul = 0.95); + } + + translate([(width - 3*boardThickness) / 2, 0, 4]) morticeBlank(morticeDims); + } + + // dovetails to connect to the side panels + translate([boardThickness, boardThickness, 4]) + rotate([0, -90, 90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + + translate([width - boardThickness, 0, 4]) + rotate([0, -90, -90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + +} + +module frontPanel(cutWeight = true) { + panelHeight = 72.2; + translate([boardThickness, 0, 0]) + difference() { + cube([width - boardThickness * 2, boardThickness, panelHeight]); + + if (cutWeight) { + triangleCutouts(h = panelHeight, rep = 1, wMul = 0.48); + translate([width - boardThickness * 2, 0, 0]) mirror([1, 0, 0]) triangleCutouts(h = panelHeight, rep = 1, wMul = 0.48);; + } + + translate([(width - 3*boardThickness) / 2, 0, 8]) morticeBlank(morticeDims); + translate([(width - 3*boardThickness) / 2, 0, 48]) morticeBlank(morticeDims); + } + + // dovetails to connect to the side panels + translate([boardThickness, boardThickness, 12]) + rotate([0, -90, 90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + + translate([width - boardThickness, 0, 12]) + rotate([0, -90, -90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + + translate([boardThickness, boardThickness, 48]) + rotate([0, -90, 90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + + translate([width - boardThickness, 0, 48]) + rotate([0, -90, -90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + +} + +module topPanel(cutWeight = true) { + panelHeight = 26; + + translate([boardThickness, 0, 0]) + difference() { + cube([width - boardThickness * 2, boardThickness, panelHeight]); + + if (cutWeight) { + triangleCutouts(h = panelHeight, wMul = 0.9); + translate([width - boardThickness * 2, 0, 0]) mirror([1, 0, 0]) triangleCutouts(h = panelHeight, wMul = 0.9); + } + + // mortice to connect to the mid piece + translate([(width - 3*boardThickness)/2, -0.1, 8]) morticeBlank(morticeDims); + } + + // dovetails to connect to the side panels + translate([boardThickness, boardThickness, 8]) + rotate([0, -90, 90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); + + translate([width - boardThickness, 0, 8]) + rotate([0, -90, -90]) + dovetail(tailHeight = boardThickness, tailWidthMin = 6, tailWidthMax = 10, depth = boardThickness); +} + +module assembled(cutWeight = true) { + spaceBetween = (width - 3*boardThickness) / 2; + + color("Tan") sidePanel(cutWeight); + color("RosyBrown") translate([1*(boardThickness + spaceBetween), 0, 0]) midPanel(cutWeight); + color("Tan") translate([2*(boardThickness + spaceBetween) + boardThickness, 0, 0]) mirror([1, 0, 0]) sidePanel(cutWeight); + + color("DarkSeaGreen") backPanel(cutWeight); + color("LightSeaGreen") translate([0, depth - toeChop - boardThickness, 0]) frontPanel(cutWeight); + + color("SkyBlue") translate([0, -toeChop, 0]) rotate([1*(-90 + supportAngle), 0, 0]) translate([0, 0, 43.9]) topPanel(cutWeight); + color("LightSteelBlue") translate([0, -toeChop, 0]) rotate([1*(-90 + supportAngle), 0, 0]) translate([0, 0, 166]) topPanel(cutWeight); +} + + +module flatPack(cutWeight = true) { + color("Tan") translate([0, 60, boardThickness]) rotate([0, 90, 0]) sidePanel(cutWeight); + color("Tan") translate([98, 144, 0]) mirror([0, 0, 1]) rotate([0, 90, 180]) sidePanel(cutWeight); + color("RosyBrown") translate([180, 300, boardThickness]) mirror([0, 1, 0]) rotate([0, 90, 90]) midPanel(cutWeight); + + color("DarkSeaGreen") translate([100, 0, 0]) rotate([90, 0, 90]) backPanel(cutWeight); + + color("LightSeaGreen") translate([120, 0, 0]) rotate([90, 0, 90]) frontPanel(cutWeight); + + color("SkyBlue") translate([194, 0, 0]) rotate([90, 0, 90]) topPanel(cutWeight); + color("LightSteelBlue") translate([222, 0, 0]) rotate([90, 0, 90]) topPanel(cutWeight); + +} + +// backPanel(); +// midPanel(); +// topPanel(); +// sidePanel(); + +// assembled(); +flatPack(); diff --git a/functional/laptop-stand-holder.scad b/functional/laptop-stand-holder.scad new file mode 100644 index 0000000..28db833 --- /dev/null +++ b/functional/laptop-stand-holder.scad @@ -0,0 +1,18 @@ +$fn=128; +length=95; + +rotate([90, 0, 0]) translate([0, length / 2, 0]) difference() { + union() { + rotate([90, 0, 0]) cylinder(d=30, h=length, center=true); + translate([10, 0, 0]) cube([20, length, 30], center=true); + } + + union() { + translate([0, -0.01, 0]) rotate([90, 0, 0]) cylinder(d=20, h=length + 0.2, center=true); + translate([20, -0.01, 0]) cube([40, length + 0.2, 20], center=true); + } +} + +//translate([-4, -4, 0]) cylinder(d=14, h=5.2); + +//translate([-1, -1]) cylinder(d=4, h=15); diff --git a/functional/shower-door-handle.scad b/functional/shower-door-handle.scad new file mode 100644 index 0000000..14d4f10 --- /dev/null +++ b/functional/shower-door-handle.scad @@ -0,0 +1,49 @@ +include <../lib/metric-machine-screws.scad> + +$fn=128; + +h_handle = 200; // Length of the handle +h_tilted = h_handle / sqrt(2); + +d_handle = 20; // Diameter of the handle +screw_distance_on_center = 88.5; + +//translate([0, 0, h_tilted / 2]) +//rotate([45, 0, 0]) +//translate([0, d_handle / 2, 0]) +difference() { + union() { + cylinder(d=d_handle, h=h_handle, center=true); // Main handle body + + for (i = [-1, 1]) { + translate([0, 17, i * (screw_distance_on_center / 2)]) + rotate([90, 0, 0]) + cylinder(d=10, h=18, center=true); + } + } + + for (i = [-1, 1]) { + translate([0, 5, i * (screw_distance_on_center / 2)]) + rotate([90, 0, 0]) + m3Nut(h=d_handle + 10, center=true, clearance=0.2); + + translate([0, 7, i * (screw_distance_on_center / 2)]) + rotate([90, 0, 0]) + cylinder(d=3.2, h=40, center=true); + } +} + +/* +translate([0, -0.2, h_tilted / 2]) +difference() { + cube([1, h_tilted, h_tilted], center=true); + + color("blue") + translate([0, h_tilted / 2, h_tilted / 2]) + rotate([45, 0, 0]) + cube([2, h_handle, h_handle], center=true); +} + +translate([0, -h_tilted / 2, 40]) +cube([40, 1, 80], center=true); +*/ diff --git a/functional/speaker-stand.scad b/functional/speaker-stand.scad new file mode 100644 index 0000000..fc8e44c --- /dev/null +++ b/functional/speaker-stand.scad @@ -0,0 +1,6 @@ +difference() { + cube([]); + + union() { + } +} diff --git a/kallax-organization/constants.scad b/kallax-organization/constants.scad index 113a5fd..18b186b 100644 --- a/kallax-organization/constants.scad +++ b/kallax-organization/constants.scad @@ -3,3 +3,4 @@ kallaxDepth = 390; // Full depth of a Kallax shelf shelfHeight = 160; // Height of a Kallax half-shelf (shelf insert) shelfWidth = 320; // Width of a Kallax half-shelf (shelf insert) +shelfDepth = kallaxDepth - 20; diff --git a/kallax-organization/quarter-drawers-pla-construction.scad b/kallax-organization/quarter-drawers-pla-construction.scad new file mode 100644 index 0000000..77be4e6 --- /dev/null +++ b/kallax-organization/quarter-drawers-pla-construction.scad @@ -0,0 +1,525 @@ +// System to divide a Kallax half-shelf into four equal drawers +// All units measured in millimeters +include <../lib/mortice-and-tenon.scad> +include <./constants.scad> + +$fn = 32; + +module sampleBox(dims, wallThickness) { + // base + cube([dims[0], dims[1], wallThickness]); + + // top + translate([0, 0, dims[2] - wallThickness]) + cube([dims[0], dims[1], wallThickness]); + + // middle shelf + translate([0, 0, (dims[2] - wallThickness) / 2]) + cube([dims[0], dims[1], wallThickness]); + + // left wall + cube([wallThickness, dims[1], dims[2]]); + + // middle divider + translate([(dims[0] - wallThickness) / 2, 0, 0]) + cube([wallThickness, dims[1], dims[2]]); + + // right wall + translate([dims[0] - wallThickness, 0, 0]) + cube([wallThickness, dims[1], dims[2]]); + +} + +module tally(count, rightAlign = false) { + groups = floor(count / 5); + rem = count % 5; + xAlign = rightAlign ? -(6 * groups) - (rem * 1.2) : 0; + translate([xAlign, 0, 0]) + union() { + if (count > 4) { + for (i = [0: max(0, groups - 1)]) { + translate([6*i, 0, 0]) for (j = [0:3]) + translate([j*1.2, 0, 0]) + cube([0.6, 4, 0.41]); + translate([6*i - 0.8, 0.6, 0]) rotate([0, 0, -60]) cube([0.6, 6.2, 0.41]); + } + } + + if (rem != 0) { + translate([6*groups, 0, 0]) + for (j = [0: rem - 1]) + translate([j*1.2, 0, 0]) + cube([0.6, 4, 0.41]); + } + } +} + +wallThickness = 4; // Thickness of walls +feltClearance = 2.5; // Clearance for felt pads + +// Dimensions for the box that fits inside a Kallax half-shelf +boxWidth = kallaxSide - 2 * feltClearance; +boxDepth = kallaxDepth; +boxHeight = shelfHeight - 2 * feltClearance; + +drawerWidth = (boxWidth - 3 * wallThickness) / 2; +drawerHeight = (boxHeight - 3 * wallThickness) / 2; + +tenonThickness = wallThickness * 0.6; +//tenon([6, 8, 2.6]); +//morticeBlank([6, 8, 2.6], 0.1); + + +// Frame for the box will be made in sections to fit on the print bed +// There are three identical horizontal layers (base, middle shelf, top) that +// will each be made of four pieces. Looking down overhead from the Z axis they +// are: +// +// x1 x2 +// ├──┴──┼─┴─┤ +// ┌─────┬───┐ ┬ +// │ C │ D │ │ +// ├─────┼───┤ ├y +// │ A │ B │ │ +// └─────┴───┘ ┴ +// +// There are three identical drawer sides for the lower drawers that are split +// into two pieces. Looking from the side, along the X axis they are: +// +// ├───y───┤ +// ┌───┬───┐ ┬ +// │ F │ E │ ├drawerHeight +// └───┴───┘ ┴ +// +// There are three identical drawer sides for the upper drawers that are split +// into two pieces. Looking from the side, along the X axis they are: +// +// ├───y───┤ +// ┌───┬───┐ ┬ +// │ H │ G │ ├drawerHeight +// └───┴───┘ ┴ + +x1 = boxWidth * 0.6; +x2 = boxWidth - x1; +y = boxDepth / 2; +tenonDims = [6, 8, tenonThickness]; +tenonZOffset = (wallThickness - tenonThickness) / 2; +verticalTenonDims = [6, wallThickness, tenonThickness]; +throughTenonDims = [6, 8 + wallThickness, tenonThickness]; +morticeClearance = 0.1; + +module leftSideHorizontalPiece(cutWeight = true) { + difference() { + cube([x1, y, wallThickness]); + + if (cutWeight) { + union() { + // cutouts to save materials + translate([2*wallThickness, 2*wallThickness, -0.1]) + cube([drawerWidth - 2*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + + translate([2*wallThickness, y/2 + wallThickness, -0.1]) + cube([drawerWidth - 2*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + + translate([drawerWidth + 3*wallThickness, 2*wallThickness, -0.1]) + cube([x1 - drawerWidth - 5*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + + translate([drawerWidth + 3*wallThickness, y/2 + 2*wallThickness, -0.1]) + cube([x1 - drawerWidth - 5*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + } + } + } + +} + +module rightSideHorizontalPiece(cutWeight = true) { + difference() { + cube([x2, y, wallThickness]); + + if (cutWeight) { + union() { + // cutouts to save materials + translate([2*wallThickness, 2*wallThickness, -0.1]) + cube([x2 - 4*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + translate([2*wallThickness, y/2 + wallThickness, -0.1]) + cube([x2 - 4*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + } + } + } +} + +module sidePiece(cutWeight = true) { + union() { + difference() { + cube([wallThickness, y, drawerHeight]); + + if (cutWeight) { + // cutouts to save materials + translate([-0.1, 2*wallThickness, 2*wallThickness]) + cube([wallThickness + 0.2, y - 4*wallThickness, drawerHeight - 3*wallThickness]); + } + } + + if (cutWeight) { + translate([0, wallThickness, 1.414*wallThickness]) + rotate([-41, 0, 0]) + cube([wallThickness, wallThickness, drawerHeight * 1.19]); + + translate([0, y - 2*wallThickness, 1.414*wallThickness]) + rotate([65, 0, 0]) + cube([wallThickness, wallThickness, drawerHeight * 1.97]); + } + } +} + +module pieceA(cutWeight = true) { + difference() { + union() { + leftSideHorizontalPiece(cutWeight); + + // tenons for joining to piece C + translate([x1*0.2, y, tenonZOffset]) tenon(tenonDims); + translate([x1*0.7, y, tenonZOffset]) tenon(tenonDims); + + // tenons for joining to piece B + translate([x1, y*0.2, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); + translate([x1, y*0.7, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); + } + + union() { + // mortices for joining to piece vertical pieces + translate([tenonZOffset, y* 0.3, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + translate([tenonZOffset, y* 0.8, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + + translate([drawerWidth + wallThickness + tenonZOffset, y* 0.3, 0]) + rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); + translate([drawerWidth + wallThickness + tenonZOffset, y* 0.8, 0]) + rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); + + // piece label + translate([2, 2, wallThickness - 0.4]) tally(1); + } + } +} + +module pieceB(cutWeight = true) { + difference() { + union() { + rightSideHorizontalPiece(cutWeight); + + // tenons for joining to piece D + translate([x2*0.2, y, tenonZOffset]) tenon(tenonDims); + translate([x2*0.7, y, tenonZOffset]) tenon(tenonDims); + } + + union() { + // mortices for joining to piece A + translate([0, y*0.2, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) + morticeBlank(tenonDims, morticeClearance); + translate([0, y*0.7, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) + morticeBlank(tenonDims, morticeClearance); + + // mortices for joining to piece vertical pieces + translate([x2 - wallThickness + tenonZOffset, y* 0.3, 0]) + rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); + + translate([x2 - wallThickness + tenonZOffset, y* 0.8, 0]) + rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); + + // piece label + translate([2, 2, wallThickness - 0.4]) tally(2); + } + } +} + +module pieceC(cutWeight = true) { + difference() { + union() { + leftSideHorizontalPiece(cutWeight); + + // tenons for joining to piece D + translate([x1, y*0.2, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); + translate([x1, y*0.7, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); + } + + union() { + + // mortices for joining to piece A + translate([x1*0.2, 0, tenonZOffset]) + morticeBlank(tenonDims, morticeClearance); + translate([x1*0.7, 0, tenonZOffset]) + morticeBlank(tenonDims, morticeClearance); + + // mortices for joining to piece F/H + translate([tenonZOffset, y* 0.3, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + translate([tenonZOffset, y* 0.8, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + + translate([drawerWidth + wallThickness + tenonZOffset, y* 0.3, 0]) + rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); + translate([drawerWidth + wallThickness + tenonZOffset, y* 0.8, 0]) + rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); + + // piece label + translate([2, 2, wallThickness - 0.4]) tally(3); + } + } +} + +module pieceD(cutWeight = true) { + difference() { + rightSideHorizontalPiece(cutWeight); + + union() { + // mortices for joining to piece C + translate([0, y*0.2, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) + morticeBlank(tenonDims, morticeClearance); + translate([0, y*0.7, tenonZOffset]) + mirror([0, 1, 0]) rotate([0, 0, -90]) + morticeBlank(tenonDims, morticeClearance); + + // mortices for joining to piece B + translate([x2*0.2, 0, tenonZOffset]) + morticeBlank(tenonDims, morticeClearance); + translate([x2*0.7, 0, tenonZOffset]) + morticeBlank(tenonDims, morticeClearance); + // mortices for joining to piece F/H + translate([x2 - wallThickness + tenonZOffset, y* 0.3, 0]) + rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); + + translate([x2 - wallThickness + tenonZOffset, y* 0.8, 0]) + rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); + + // piece label + translate([2, 2, wallThickness - 0.4]) tally(4); + } + } +} + +module pieceE(cutWeight = true) { + difference() { + union() { + sidePiece(cutWeight); + + // tenons for joining to horizontal pieces + translate([tenonZOffset, y*0.3, 0]) mirror([1, 0, 0]) + rotate([-90, 0, 90]) tenon(verticalTenonDims); + translate([tenonZOffset, y*0.8, 0]) mirror([1, 0, 0]) + rotate([-90, 0, 90]) tenon(verticalTenonDims); + + // tenon for joining to piece F + translate([tenonZOffset, y, drawerHeight/2]) mirror([0, 0, 1]) + rotate([0, 90, 00]) tenon(tenonDims); + + // tenons for joining to piece G + translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) + tenon(throughTenonDims); + translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) + tenon(throughTenonDims); + //translate([tenonZOffset, y*0.8, 0]) mirror([1, 0, 0]) + // rotate([-90, 0, 90]) tenon(verticalTenonDims); + } + + // piece label + translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(5, true); + } +} + +module pieceF(cutWeight = true) { + difference() { + union() { + sidePiece(cutWeight); + + // tenons for joining to horizontal pieces + translate([tenonZOffset, y*0.3, 0]) mirror([1, 0, 0]) + rotate([-90, 0, 90]) tenon(verticalTenonDims); + translate([tenonZOffset, y*0.8, 0]) mirror([1, 0, 0]) + rotate([-90, 0, 90]) tenon(verticalTenonDims); + + // tenons for joining to piece H + translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) + tenon(throughTenonDims); + translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) + tenon(throughTenonDims); + + } + + union() { + // mortice for joining to piece E + translate([tenonZOffset, 0, drawerHeight/2]) mirror([0, 0, 1]) + rotate([0, 90, 00]) tenon(tenonDims); + + // piece label + translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(6, true); + } + } +} + +module pieceG(cutWeight = true) { + difference() { + union() { + sidePiece(cutWeight); + + // tenons for joining to vertical pieces above + translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) + tenon(verticalTenonDims); + translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) + tenon(verticalTenonDims); + + // tenon for joining to piece H + translate([tenonZOffset, y, drawerHeight/2]) mirror([0, 0, 1]) + rotate([0, 90, 00]) tenon(tenonDims); + + + } + + union() { + // mortices for joining to piece E + translate([tenonZOffset, y*0.3, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + translate([tenonZOffset, y*0.8, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + + // piece label + translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(7, true); + } + } +} + +module pieceH(cutWeight = true) { + difference() { + union() { + sidePiece(cutWeight); + + // tenons for joining to vertical pieces above + translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) + tenon(verticalTenonDims); + translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) + tenon(verticalTenonDims); + } + + union() { + // mortices for joining to piece F + translate([tenonZOffset, y*0.3, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + translate([tenonZOffset, y*0.8, 0]) rotate([90, 0, 90]) + morticeBlank(verticalTenonDims, morticeClearance); + + // mortice for joining to piece G + translate([tenonZOffset, 0, drawerHeight/2]) mirror([0, 0, 1]) + rotate([0, 90, 00]) tenon(tenonDims); + + // piece label + translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(8, true); + } + } +} + + +// Mortice and tenon test pieces +// rotate([0, 90, 0]) union() { +// cube([10, 16, wallThickness]); +// translate([2, 16, tenonZOffset]) tenon(tenonDims); +// } +// +// translate([10, 0, 0]) rotate([0, 90, 0]) difference() { +// cube([10, 16, wallThickness]); +// translate([2 - 0.1, 16 - 0.1, tenonZOffset - 0.1]) +// mirror([0, 1, 0]) morticeBlank(tenonDims, morticeClearance); +// } + +module completeBox(gap = 10, cutWeight = true) { + + // vertical layers + for (i = [0:2]) { + z = i * (wallThickness + 1.5*gap + drawerHeight); + translate([0, 0, z]) pieceA(cutWeight); + translate([x1 + gap, 0, z]) pieceB(cutWeight); + translate([0, y + gap, z]) pieceC(cutWeight); + translate([x1 + gap, y + gap, z]) pieceD(cutWeight); + } + + // lower box walls + for (i = [0:2]) { + x = i * (wallThickness + drawerWidth) + + (i == 2 ? gap : 0); + + translate([x, 0, wallThickness + gap]) pieceE(cutWeight); + translate([x, y + gap, wallThickness + gap]) pieceF(cutWeight); + } + + // upper box walls + for (i = [0:2]) { + x = i * (wallThickness + drawerWidth) + + (i == 2 ? gap : 0); + + translate([x, 0, drawerHeight + 2*wallThickness + 2*gap]) pieceG(cutWeight); + translate([x, y + gap, drawerHeight + 2*wallThickness + 2*gap]) pieceH(cutWeight); + } + +} + +module printStack() { + for (i = [0:2]) { + translate([0, 0, i * (wallThickness + 0.4)]) pieceA(); + translate([0, 0, (i+3) * (wallThickness + 0.4)]) pieceC(); + translate([0, 0, (i+6) * (wallThickness + 0.4)]) pieceB(); + translate([0, 0, (i+9) * (wallThickness + 0.4)]) pieceD(); + + translate([ + 0, + y + drawerHeight +throughTenonDims[1] + 4, + i * (wallThickness + 0.4) + wallThickness]) + rotate([90, 90, 0]) pieceE(); + + translate([0, + y + drawerHeight +throughTenonDims[1] + 4, + (i+3) * (wallThickness + 0.4) + wallThickness]) + rotate([90, 90, 0]) pieceF(); + + translate([ + 0, + y + drawerHeight +throughTenonDims[1] + 4, + (i+6) * (wallThickness + 0.4) + wallThickness]) + rotate([90, 90, 0]) pieceG(); + + translate([ + 0, + y + drawerHeight +throughTenonDims[1] + 4, + (i+9) * (wallThickness + 0.4) + wallThickness]) + rotate([90, 90, 0]) pieceH(); + + } +} + +module testStack() { + for (i = [0:2]) { + translate([0, 0, i * (wallThickness + 0.4)]) pieceA(); + translate([0, 0, (i+3) * (wallThickness + 0.4)]) pieceB(); + + translate([ + 0, + y + drawerHeight +throughTenonDims[1] + 4, + i * (wallThickness + 0.4) + wallThickness]) + rotate([90, 90, 0]) pieceE(); + + translate([0, + y + drawerHeight +throughTenonDims[1] + 4, + (i+3) * (wallThickness + 0.4) + wallThickness]) + rotate([90, 90, 0]) pieceF(); + + } +} + +completeBox(gap = 10, cutWeight = false); +// testStack(); diff --git a/kallax-organization/quarter-drawers.scad b/kallax-organization/quarter-drawers.scad index 77be4e6..db3a07a 100644 --- a/kallax-organization/quarter-drawers.scad +++ b/kallax-organization/quarter-drawers.scad @@ -1,525 +1,387 @@ -// System to divide a Kallax half-shelf into four equal drawers -// All units measured in millimeters -include <../lib/mortice-and-tenon.scad> include <./constants.scad> +include <../lib/metric-machine-screws.scad> -$fn = 32; +// all measurements in mm +// boardThickness = 4.7; // 1/8" plywood +boardThickness = 7.35; +feltThickness = 2.5; +feltWidth = 12; +clipThickness = boardThickness + 2*feltThickness; +clipWallThickness = 4; +clipFlangeLength = 24; +clipFlangeWidth = 16; -module sampleBox(dims, wallThickness) { - // base - cube([dims[0], dims[1], wallThickness]); +// measurements for the wooden panels to cut: +// +// ───────────── - top board (A) +// │ │ │ +// │───────────│ +// │ │ │ +// │───────────│ +// +// +// top board: 320.0 x 370.0 +// bottom board: 305.6 x 370.0 (320 - 2*4.7 - 2*2.5) x 370 +// side boards: 152.8 x 370.0 (160 - 4.7 - 2.5) x 370 +// inner boards: 70.45 x 370.0 ((160 - 3*4.7 - 2*2.5)/2) x 370 +// - // top - translate([0, 0, dims[2] - wallThickness]) - cube([dims[0], dims[1], wallThickness]); +module fastenerBlank() { + translate([0, 0.1 + 2 * clipWallThickness + boardThickness, 0]) + rotate([90, 0, 0]) + m3Nut(h=2.41); - // middle shelf - translate([0, 0, (dims[2] - wallThickness) / 2]) - cube([dims[0], dims[1], wallThickness]); + translate([0, 2.4, 0]) + rotate([90, 0, 0]) + m3Nut(h=2.41); - // left wall - cube([wallThickness, dims[1], dims[2]]); + translate([0, 0.1 + 2 * clipWallThickness + boardThickness, 0]) + rotate([90, 0, 0]) + cylinder(d = 3.2, center = false, $fn=128, + h = 0.2 + 2 * clipWallThickness + boardThickness); +} - // middle divider - translate([(dims[0] - wallThickness) / 2, 0, 0]) - cube([wallThickness, dims[1], dims[2]]); +module dowelBlank() { + translate([0, 0.1 + 2 * clipWallThickness + boardThickness, 0]) + rotate([90, 0, 0]) + cylinder(d = 3.175, center = false, $fn=128, + h = 0.2 + 2 * clipWallThickness + boardThickness); +} - // right wall - translate([dims[0] - wallThickness, 0, 0]) - cube([wallThickness, dims[1], dims[2]]); +module cornerClipA() { + difference() { + cube([clipFlangeLength, clipFlangeLength, clipFlangeLength]); + + translate([clipWallThickness, clipWallThickness, clipWallThickness]) + union() { + cube([clipFlangeLength, boardThickness, clipFlangeLength]); + cube([boardThickness, clipFlangeLength, clipFlangeLength]); + } + + translate([ + boardThickness + 2*clipWallThickness, + boardThickness + 2*clipWallThickness, + -1 ]) + cube([clipFlangeLength, clipFlangeLength, clipFlangeLength + 2]); + + for (i = [-1, 0]) { + rotate([0, 0, i * 180]) + mirror([i * 1, i * 1, 0]) + translate([ + clipFlangeLength - clipWallThickness, + 0, + clipFlangeLength - clipWallThickness]) + dowelBlank(); + } + } +} + +module cornerClip() { + difference() { + cube([clipThickness, clipThickness, clipThickness]); + + translate([feltThickness, feltThickness, feltThickness]) + cube([boardThickness, clipThickness, clipThickness]); + + translate([feltThickness, feltThickness, feltThickness]) + cube([clipThickness, boardThickness, clipThickness]); + } +} + +module sideClipA() { + translate([clipFlangeLength, 0, 0]) + difference() { + translate([-clipFlangeLength, 0, 0]) + cube([2 * clipFlangeLength, clipFlangeLength, clipFlangeLength + boardThickness]); + + translate([0, clipWallThickness, clipWallThickness]) + union() { + translate([-0.1 - clipFlangeLength, 0, 0]) + cube([2*clipFlangeLength + 0.2, clipFlangeLength, boardThickness]); + + translate([-boardThickness/2, 0, 0]) + cube([boardThickness, clipFlangeLength, clipFlangeLength + boardThickness]); + } + + for (i = [0, 1]) { + mirror([i, 0, 0]) + translate([ + clipWallThickness + boardThickness/2, + -0.1, + 2*clipWallThickness + boardThickness]) + cube(clipFlangeLength+0.2); + } + + for (i = [0:2]) { + translate([0, 0, boardThickness/2 + clipWallThickness]) + rotate([0, i*-90, 0]) + translate([ + clipFlangeLength - 2*clipWallThickness, + clipFlangeLength - 2*clipWallThickness, + -boardThickness/2 - clipWallThickness]) + rotate([90, 0, 0]) + dowelBlank(); + } + } +} + +module sideClip() { + difference() { + cube([clipThickness, 2 * clipThickness, clipThickness]); + + translate([-0.1, feltThickness, feltThickness]) + cube([clipThickness + 0.2, boardThickness, clipThickness]); + + translate([feltThickness, feltThickness, feltThickness]) + cube([boardThickness, 2 * clipThickness, clipThickness]); + } +} + +module crossClipA() { + cutoutLength = 2*clipFlangeLength + boardThickness; + //translate([cutoutLength/2, 0, cutoutLength/2]) + difference() { + translate([-cutoutLength/2, 0, -cutoutLength/2]) + cube([cutoutLength, clipFlangeLength, cutoutLength]); + + translate([-cutoutLength/2-0.1, clipWallThickness, -boardThickness/2]) + cube([2*clipFlangeLength + boardThickness + 0.2, clipFlangeLength, boardThickness]); + + translate([-boardThickness/2, clipWallThickness, -cutoutLength/2-0.1]) + cube([boardThickness, clipFlangeLength, 2*clipFlangeLength + boardThickness + 0.2]); + + for (i = [0:3]) { + rotate([0, i*90, 0]) + translate([ + clipWallThickness + boardThickness/2, + -0.1, + clipWallThickness + boardThickness/2]) + cube(clipFlangeLength+0.2); + } + + for (i = [0:3]) { + rotate([0, i*-90, 0]) + translate([clipFlangeLength - clipWallThickness, clipFlangeLength - 1.5*clipWallThickness, -clipWallThickness - boardThickness/2]) + rotate([90, 0, 0]) + dowelBlank(); + } + } +} + +module printableSet() { + difference() { + translate([0, 0, -1.4]) + union() { + for (i = [0:7]) + translate([i * (clipThickness + 2), clipThickness, 0]) + rotate([45, 0, 0]) + cornerClip(); + + for (i = [0:7]) + translate([i * (clipThickness + 2), 3 * clipThickness, 0]) + rotate([0, 0, 0]) + sideClip(); + + for (i = [0:1]) + translate([i * (2 * clipThickness + 2), 7 * clipThickness, 0]) + rotate([45, 0, 0]) + crossClip(); + } + + translate([-1, -1, -1.4]) cube([100, 100, 1.4]); + } +} + +module printableSetA() { + difference() { + union() { + translate([20, 0, -4.82]) + for (i = [0:7]) + translate([i%4 * (clipFlangeLength + 16), 2*floor(i/4) * clipFlangeLength, 0]) + rotate([45, -45, 0]) + cornerClipA(); + + translate([0, 0, -2]) + for (i = [0:7]) + translate([i%4 * (2*clipFlangeLength + 16), (4 + 2*floor(i/4)) * clipFlangeLength, 0]) + rotate([45, 0, 0]) + sideClipA(); + + for (i = [0:1]) + translate([30 + i * (2 * clipFlangeLength + 16), 8.5 * clipFlangeLength, 0]) + rotate([90, 0, 0]) + crossClipA(); + } + + translate([-20, -20, -10]) cube([500, 300, 10]); + } +} + +module containingBox(boxDims) { + difference() { + cube([boxDims[0] + 12, boxDims[1], boxDims[2] + 12]); + translate([6, -0.1, 6]) + cube([boxDims[0], boxDims[1] + 0.2, boxDims[2]]); + } +} + +module feltClearanceBox(boxDims) { + difference() { + cube([boxDims[0], boxDims[1], boxDims[2]]); + + translate([feltThickness, -0.1, feltThickness]) + cube([boxDims[0] - 2*feltThickness, boxDims[1] + 0.2, boxDims[2] - 2*feltThickness]); + } +} + +module topPanel(boxDims) { + difference() { + color("BurlyWood") cube([boxDims[0], boxDims[1], boardThickness]); + color("black") translate([10, 10, boardThickness - 1]) linear_extrude(1.1) + text(font="Iosevka", size=16, "top - plywood"); + } +} + +module sidePanel(boxDims) { + difference() { + color("Wheat") cube([boxDims[2] - boardThickness, boxDims[1], boardThickness]); + color("black") rotate([0, 0, -90]) translate([-10, 10, boardThickness - 1]) linear_extrude(1.1) + text(font="Iosevka", halign = "right", size=16, "side - plywood"); + } +} + +module innerPanel(boxDims) { + difference() { + color("BlanchedAlmond") cube([(boxDims[2] - 3*boardThickness) / 2, boxDims[1], boardThickness]); + color("black") rotate([0, 0, -90]) translate([-10, 10, boardThickness - 1]) linear_extrude(1.1) + text(font="Iosevka", halign = "right", size=16, "inner panel - plywood"); + } +} + +module bottomPanel(boxDims) { + difference() { + color ("Tan") cube([boxDims[0] - 2*boardThickness, boxDims[1], boardThickness]); + color("black") translate([10, 10, boardThickness - 1]) linear_extrude(1.1) + text(font="Iosevka", size=16, "bottom - plywood"); + } +} + +// TODO +module drawerFacePlate(outerBoxDims, includeClips = false) { } -module tally(count, rightAlign = false) { - groups = floor(count / 5); - rem = count % 5; - xAlign = rightAlign ? -(6 * groups) - (rem * 1.2) : 0; - translate([xAlign, 0, 0]) +module drawerBottom(outerBoxDims, includeClips = false) { +} + +module drawerSide(outerBoxDims, includeClips = false) { +} + +module assembled(outerBoxDims, includeClips = false) { + translate([-6, 0, -6]) + color("darkgrey") + containingBox(outerBoxDims); + + color("brown") + feltClearanceBox(outerBoxDims); + + clipOffset = includeClips ? clipWallThickness : 0; + + innerBoxDims = includeClips ? + [ outerBoxDims[0] - 2*feltThickness - 2*clipWallThickness, + outerBoxDims[1] - 2*clipWallThickness, + outerBoxDims[2] - 2*feltThickness - 2*clipWallThickness ] : + [ outerBoxDims[0] - 2*feltThickness, + outerBoxDims[1], + outerBoxDims[2] - 2*feltThickness ]; + + translate([feltThickness, 0, feltThickness]) union() { - if (count > 4) { - for (i = [0: max(0, groups - 1)]) { - translate([6*i, 0, 0]) for (j = [0:3]) - translate([j*1.2, 0, 0]) - cube([0.6, 4, 0.41]); - translate([6*i - 0.8, 0.6, 0]) rotate([0, 0, -60]) cube([0.6, 6.2, 0.41]); - } + translate([ clipOffset, clipOffset, clipOffset]) + union() { + translate([0, 0, innerBoxDims[2] - boardThickness]) topPanel(innerBoxDims); + + translate([boardThickness, 0, 0]) rotate([0, -90, 0]) sidePanel(innerBoxDims); + translate([innerBoxDims[0], 0, 0]) rotate([0, -90, 0]) sidePanel(innerBoxDims); + + translate([(innerBoxDims[0] + boardThickness)/2, 0, boardThickness]) rotate([0, -90, 0]) innerPanel(innerBoxDims); + translate([(innerBoxDims[0] + boardThickness)/2, 0, 2*boardThickness + (innerBoxDims[2] - 3*boardThickness)/2]) rotate([0, -90, 0]) innerPanel(innerBoxDims); + + translate([boardThickness, 0, boardThickness + (innerBoxDims[2] - 3*boardThickness)/2]) bottomPanel(innerBoxDims); + translate([boardThickness, 0, 0]) bottomPanel(innerBoxDims); } - if (rem != 0) { - translate([6*groups, 0, 0]) - for (j = [0: rem - 1]) - translate([j*1.2, 0, 0]) - cube([0.6, 4, 0.41]); - } - } -} + if (includeClips) { + for(i = [0:1]) { + translate([0, i * (2 * clipWallThickness + innerBoxDims[1]), 0]) + mirror([0, i * 1, 0]) + union() { + rotate([-90, -90, 0]) + cornerClipA(); -wallThickness = 4; // Thickness of walls -feltClearance = 2.5; // Clearance for felt pads + translate([0, 0, 2 * clipWallThickness + innerBoxDims[2]]) + rotate([-90, 0, 0]) + cornerClipA(); -// Dimensions for the box that fits inside a Kallax half-shelf -boxWidth = kallaxSide - 2 * feltClearance; -boxDepth = kallaxDepth; -boxHeight = shelfHeight - 2 * feltClearance; + translate([2 * clipWallThickness + innerBoxDims[0], 0, 0]) + rotate([-90, -180, 0]) + cornerClipA(); -drawerWidth = (boxWidth - 3 * wallThickness) / 2; -drawerHeight = (boxHeight - 3 * wallThickness) / 2; + translate([2 * clipWallThickness + innerBoxDims[0], 0, 2 * clipWallThickness + innerBoxDims[2]]) + rotate([-90, -270, 0]) + cornerClipA(); -tenonThickness = wallThickness * 0.6; -//tenon([6, 8, 2.6]); -//morticeBlank([6, 8, 2.6], 0.1); + translate([clipWallThickness + innerBoxDims[0]/2 - clipFlangeLength, 0, 0]) + sideClipA(); + translate([clipWallThickness + innerBoxDims[0]/2 + clipFlangeLength, 0, 2 * clipWallThickness + innerBoxDims[2]]) + rotate([0, 180, 0]) + sideClipA(); -// Frame for the box will be made in sections to fit on the print bed -// There are three identical horizontal layers (base, middle shelf, top) that -// will each be made of four pieces. Looking down overhead from the Z axis they -// are: -// -// x1 x2 -// ├──┴──┼─┴─┤ -// ┌─────┬───┐ ┬ -// │ C │ D │ │ -// ├─────┼───┤ ├y -// │ A │ B │ │ -// └─────┴───┘ ┴ -// -// There are three identical drawer sides for the lower drawers that are split -// into two pieces. Looking from the side, along the X axis they are: -// -// ├───y───┤ -// ┌───┬───┐ ┬ -// │ F │ E │ ├drawerHeight -// └───┴───┘ ┴ -// -// There are three identical drawer sides for the upper drawers that are split -// into two pieces. Looking from the side, along the X axis they are: -// -// ├───y───┤ -// ┌───┬───┐ ┬ -// │ H │ G │ ├drawerHeight -// └───┴───┘ ┴ + translate([0, 0, innerBoxDims[2]/2 + clipFlangeLength + clipWallThickness]) + rotate([0, 90, 0]) + sideClipA(); -x1 = boxWidth * 0.6; -x2 = boxWidth - x1; -y = boxDepth / 2; -tenonDims = [6, 8, tenonThickness]; -tenonZOffset = (wallThickness - tenonThickness) / 2; -verticalTenonDims = [6, wallThickness, tenonThickness]; -throughTenonDims = [6, 8 + wallThickness, tenonThickness]; -morticeClearance = 0.1; + translate([innerBoxDims[0] + 2*clipWallThickness, 0, innerBoxDims[2]/2 - clipFlangeLength + clipWallThickness]) + rotate([0, 270, 0]) + sideClipA(); -module leftSideHorizontalPiece(cutWeight = true) { - difference() { - cube([x1, y, wallThickness]); - - if (cutWeight) { - union() { - // cutouts to save materials - translate([2*wallThickness, 2*wallThickness, -0.1]) - cube([drawerWidth - 2*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); - - translate([2*wallThickness, y/2 + wallThickness, -0.1]) - cube([drawerWidth - 2*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); - - translate([drawerWidth + 3*wallThickness, 2*wallThickness, -0.1]) - cube([x1 - drawerWidth - 5*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); - - translate([drawerWidth + 3*wallThickness, y/2 + 2*wallThickness, -0.1]) - cube([x1 - drawerWidth - 5*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); - } - } - } - -} - -module rightSideHorizontalPiece(cutWeight = true) { - difference() { - cube([x2, y, wallThickness]); - - if (cutWeight) { - union() { - // cutouts to save materials - translate([2*wallThickness, 2*wallThickness, -0.1]) - cube([x2 - 4*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); - translate([2*wallThickness, y/2 + wallThickness, -0.1]) - cube([x2 - 4*wallThickness, y/2 - 3*wallThickness, wallThickness + 0.2]); + translate([innerBoxDims[0]/2 + clipWallThickness, 0, innerBoxDims[2]/2 + clipWallThickness]) + crossClipA(); + } } } } } -module sidePiece(cutWeight = true) { - union() { - difference() { - cube([wallThickness, y, drawerHeight]); +module allCutParts(outerBoxDims, includeClips = false) { + innerBoxDims = includeClips ? + [ outerBoxDims[0] - 2*feltThickness - 2*clipWallThickness, + outerBoxDims[1] - 2*clipWallThickness, + outerBoxDims[2] - 2*feltThickness - 2*clipWallThickness ] : + [ outerBoxDims[0] - 2*feltThickness, + outerBoxDims[1], + outerBoxDims[2] - 2*feltThickness ]; - if (cutWeight) { - // cutouts to save materials - translate([-0.1, 2*wallThickness, 2*wallThickness]) - cube([wallThickness + 0.2, y - 4*wallThickness, drawerHeight - 3*wallThickness]); - } - } + topPanel(innerBoxDims); - if (cutWeight) { - translate([0, wallThickness, 1.414*wallThickness]) - rotate([-41, 0, 0]) - cube([wallThickness, wallThickness, drawerHeight * 1.19]); + translate([innerBoxDims[0] + 8, 0, 0]) + bottomPanel(innerBoxDims); - translate([0, y - 2*wallThickness, 1.414*wallThickness]) - rotate([65, 0, 0]) - cube([wallThickness, wallThickness, drawerHeight * 1.97]); - } - } -} + translate([0, innerBoxDims[1] + 8, 0]) + sidePanel(innerBoxDims); -module pieceA(cutWeight = true) { - difference() { - union() { - leftSideHorizontalPiece(cutWeight); - - // tenons for joining to piece C - translate([x1*0.2, y, tenonZOffset]) tenon(tenonDims); - translate([x1*0.7, y, tenonZOffset]) tenon(tenonDims); - - // tenons for joining to piece B - translate([x1, y*0.2, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); - translate([x1, y*0.7, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); - } - - union() { - // mortices for joining to piece vertical pieces - translate([tenonZOffset, y* 0.3, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - translate([tenonZOffset, y* 0.8, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - - translate([drawerWidth + wallThickness + tenonZOffset, y* 0.3, 0]) - rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); - translate([drawerWidth + wallThickness + tenonZOffset, y* 0.8, 0]) - rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); - - // piece label - translate([2, 2, wallThickness - 0.4]) tally(1); - } - } -} - -module pieceB(cutWeight = true) { - difference() { - union() { - rightSideHorizontalPiece(cutWeight); - - // tenons for joining to piece D - translate([x2*0.2, y, tenonZOffset]) tenon(tenonDims); - translate([x2*0.7, y, tenonZOffset]) tenon(tenonDims); - } - - union() { - // mortices for joining to piece A - translate([0, y*0.2, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) - morticeBlank(tenonDims, morticeClearance); - translate([0, y*0.7, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) - morticeBlank(tenonDims, morticeClearance); - - // mortices for joining to piece vertical pieces - translate([x2 - wallThickness + tenonZOffset, y* 0.3, 0]) - rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); - - translate([x2 - wallThickness + tenonZOffset, y* 0.8, 0]) - rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); - - // piece label - translate([2, 2, wallThickness - 0.4]) tally(2); - } - } -} - -module pieceC(cutWeight = true) { - difference() { - union() { - leftSideHorizontalPiece(cutWeight); - - // tenons for joining to piece D - translate([x1, y*0.2, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); - translate([x1, y*0.7, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) tenon(tenonDims); - } - - union() { - - // mortices for joining to piece A - translate([x1*0.2, 0, tenonZOffset]) - morticeBlank(tenonDims, morticeClearance); - translate([x1*0.7, 0, tenonZOffset]) - morticeBlank(tenonDims, morticeClearance); - - // mortices for joining to piece F/H - translate([tenonZOffset, y* 0.3, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - translate([tenonZOffset, y* 0.8, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - - translate([drawerWidth + wallThickness + tenonZOffset, y* 0.3, 0]) - rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); - translate([drawerWidth + wallThickness + tenonZOffset, y* 0.8, 0]) - rotate([90, 0, 90]) morticeBlank(verticalTenonDims, morticeClearance); - - // piece label - translate([2, 2, wallThickness - 0.4]) tally(3); - } - } -} - -module pieceD(cutWeight = true) { - difference() { - rightSideHorizontalPiece(cutWeight); - - union() { - // mortices for joining to piece C - translate([0, y*0.2, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) - morticeBlank(tenonDims, morticeClearance); - translate([0, y*0.7, tenonZOffset]) - mirror([0, 1, 0]) rotate([0, 0, -90]) - morticeBlank(tenonDims, morticeClearance); - - // mortices for joining to piece B - translate([x2*0.2, 0, tenonZOffset]) - morticeBlank(tenonDims, morticeClearance); - translate([x2*0.7, 0, tenonZOffset]) - morticeBlank(tenonDims, morticeClearance); - // mortices for joining to piece F/H - translate([x2 - wallThickness + tenonZOffset, y* 0.3, 0]) - rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); - - translate([x2 - wallThickness + tenonZOffset, y* 0.8, 0]) - rotate([90, 0, 90]) morticeBlank(tenonDims, morticeClearance); - - // piece label - translate([2, 2, wallThickness - 0.4]) tally(4); - } - } -} - -module pieceE(cutWeight = true) { - difference() { - union() { - sidePiece(cutWeight); - - // tenons for joining to horizontal pieces - translate([tenonZOffset, y*0.3, 0]) mirror([1, 0, 0]) - rotate([-90, 0, 90]) tenon(verticalTenonDims); - translate([tenonZOffset, y*0.8, 0]) mirror([1, 0, 0]) - rotate([-90, 0, 90]) tenon(verticalTenonDims); - - // tenon for joining to piece F - translate([tenonZOffset, y, drawerHeight/2]) mirror([0, 0, 1]) - rotate([0, 90, 00]) tenon(tenonDims); - - // tenons for joining to piece G - translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) - tenon(throughTenonDims); - translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) - tenon(throughTenonDims); - //translate([tenonZOffset, y*0.8, 0]) mirror([1, 0, 0]) - // rotate([-90, 0, 90]) tenon(verticalTenonDims); - } - - // piece label - translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(5, true); - } -} - -module pieceF(cutWeight = true) { - difference() { - union() { - sidePiece(cutWeight); - - // tenons for joining to horizontal pieces - translate([tenonZOffset, y*0.3, 0]) mirror([1, 0, 0]) - rotate([-90, 0, 90]) tenon(verticalTenonDims); - translate([tenonZOffset, y*0.8, 0]) mirror([1, 0, 0]) - rotate([-90, 0, 90]) tenon(verticalTenonDims); - - // tenons for joining to piece H - translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) - tenon(throughTenonDims); - translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) - tenon(throughTenonDims); - - } - - union() { - // mortice for joining to piece E - translate([tenonZOffset, 0, drawerHeight/2]) mirror([0, 0, 1]) - rotate([0, 90, 00]) tenon(tenonDims); - - // piece label - translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(6, true); - } - } -} - -module pieceG(cutWeight = true) { - difference() { - union() { - sidePiece(cutWeight); - - // tenons for joining to vertical pieces above - translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) - tenon(verticalTenonDims); - translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) - tenon(verticalTenonDims); - - // tenon for joining to piece H - translate([tenonZOffset, y, drawerHeight/2]) mirror([0, 0, 1]) - rotate([0, 90, 00]) tenon(tenonDims); - - - } - - union() { - // mortices for joining to piece E - translate([tenonZOffset, y*0.3, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - translate([tenonZOffset, y*0.8, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - - // piece label - translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(7, true); - } - } -} - -module pieceH(cutWeight = true) { - difference() { - union() { - sidePiece(cutWeight); - - // tenons for joining to vertical pieces above - translate([tenonZOffset, y*0.3, drawerHeight]) rotate([90, 0, 90]) - tenon(verticalTenonDims); - translate([tenonZOffset, y*0.8, drawerHeight]) rotate([90, 0, 90]) - tenon(verticalTenonDims); - } - - union() { - // mortices for joining to piece F - translate([tenonZOffset, y*0.3, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - translate([tenonZOffset, y*0.8, 0]) rotate([90, 0, 90]) - morticeBlank(verticalTenonDims, morticeClearance); - - // mortice for joining to piece G - translate([tenonZOffset, 0, drawerHeight/2]) mirror([0, 0, 1]) - rotate([0, 90, 00]) tenon(tenonDims); - - // piece label - translate([0.4, 2, 2]) rotate([90, 0, -90]) tally(8, true); - } - } -} - - -// Mortice and tenon test pieces -// rotate([0, 90, 0]) union() { -// cube([10, 16, wallThickness]); -// translate([2, 16, tenonZOffset]) tenon(tenonDims); -// } -// -// translate([10, 0, 0]) rotate([0, 90, 0]) difference() { -// cube([10, 16, wallThickness]); -// translate([2 - 0.1, 16 - 0.1, tenonZOffset - 0.1]) -// mirror([0, 1, 0]) morticeBlank(tenonDims, morticeClearance); -// } - -module completeBox(gap = 10, cutWeight = true) { - - // vertical layers - for (i = [0:2]) { - z = i * (wallThickness + 1.5*gap + drawerHeight); - translate([0, 0, z]) pieceA(cutWeight); - translate([x1 + gap, 0, z]) pieceB(cutWeight); - translate([0, y + gap, z]) pieceC(cutWeight); - translate([x1 + gap, y + gap, z]) pieceD(cutWeight); - } - - // lower box walls - for (i = [0:2]) { - x = i * (wallThickness + drawerWidth) + - (i == 2 ? gap : 0); - - translate([x, 0, wallThickness + gap]) pieceE(cutWeight); - translate([x, y + gap, wallThickness + gap]) pieceF(cutWeight); - } - - // upper box walls - for (i = [0:2]) { - x = i * (wallThickness + drawerWidth) + - (i == 2 ? gap : 0); - - translate([x, 0, drawerHeight + 2*wallThickness + 2*gap]) pieceG(cutWeight); - translate([x, y + gap, drawerHeight + 2*wallThickness + 2*gap]) pieceH(cutWeight); - } + translate([innerBoxDims[2], innerBoxDims[1] + 8, 0]) + innerPanel(innerBoxDims); } -module printStack() { - for (i = [0:2]) { - translate([0, 0, i * (wallThickness + 0.4)]) pieceA(); - translate([0, 0, (i+3) * (wallThickness + 0.4)]) pieceC(); - translate([0, 0, (i+6) * (wallThickness + 0.4)]) pieceB(); - translate([0, 0, (i+9) * (wallThickness + 0.4)]) pieceD(); +shelfDims = [shelfWidth, shelfDepth, shelfHeight]; +//assembled(shelfDims); - translate([ - 0, - y + drawerHeight +throughTenonDims[1] + 4, - i * (wallThickness + 0.4) + wallThickness]) - rotate([90, 90, 0]) pieceE(); +//translate([shelfWidth + 20, 0, 0]) +//allCutParts(shelfDims); - translate([0, - y + drawerHeight +throughTenonDims[1] + 4, - (i+3) * (wallThickness + 0.4) + wallThickness]) - rotate([90, 90, 0]) pieceF(); - - translate([ - 0, - y + drawerHeight +throughTenonDims[1] + 4, - (i+6) * (wallThickness + 0.4) + wallThickness]) - rotate([90, 90, 0]) pieceG(); - - translate([ - 0, - y + drawerHeight +throughTenonDims[1] + 4, - (i+9) * (wallThickness + 0.4) + wallThickness]) - rotate([90, 90, 0]) pieceH(); - - } -} - -module testStack() { - for (i = [0:2]) { - translate([0, 0, i * (wallThickness + 0.4)]) pieceA(); - translate([0, 0, (i+3) * (wallThickness + 0.4)]) pieceB(); - - translate([ - 0, - y + drawerHeight +throughTenonDims[1] + 4, - i * (wallThickness + 0.4) + wallThickness]) - rotate([90, 90, 0]) pieceE(); - - translate([0, - y + drawerHeight +throughTenonDims[1] + 4, - (i+3) * (wallThickness + 0.4) + wallThickness]) - rotate([90, 90, 0]) pieceF(); - - } -} - -completeBox(gap = 10, cutWeight = false); -// testStack(); +//translate([300, shelfDepth + 40, 0]) +//rotate([0, 0, 90]) +printableSetA(); diff --git a/replacement-parts/alesis-cymbal-support.scad b/replacement-parts/alesis-cymbal-support.scad new file mode 100644 index 0000000..18a447f --- /dev/null +++ b/replacement-parts/alesis-cymbal-support.scad @@ -0,0 +1,72 @@ +$fn = 256; + +d_i = 10.8; // Inner diameter of the cymbal mount hole + +d_o_top = 24; // Diameter of the outer top of the cymbal support +h_top = 11; // Height of the top part of the cymbal support + +d_o_bot = 19; // Diameter of the outer bottom of the cymbal support +h_bot = 10.2; // Height of the bottom part of the cymbal support + +h_dome = 6.8; // Height of the dome part of the cymbal support +h_neck = 5; // Height of the neck part of the cymbal support + +h_flange = 17.5; +w_flange = 3; + +h_full = h_bot + h_neck + h_top + h_dome; + +difference() { + union() { + // Bottom part of the cymbal support + translate([0, 0, h_bot/2 + 0.1]) + cylinder(h = h_bot + 0.2, d = d_o_bot, center = true); + + // Neck of the cymbal support + translate([0, 0, h_bot + h_neck / 2]) + cylinder(h = h_neck, d1 = d_o_bot, d2 = d_o_top, center = true); + + // Top part of the cymbal support + translate([0, 0, h_bot + h_neck + h_top/2 + 0.1]) + cylinder(h = h_top + 0.2, d = d_o_top, center = true); + + // Dome on top of the cymbal support + translate([0, 0, h_bot + h_neck + h_top]) + scale([1, 1, (2*h_dome + 2) / d_o_top]) + sphere(d = d_o_top); + + // Flange at the bottom of the cymbal support + translate([-w_flange / 2, d_i / 2, 0]) cube([w_flange, 22, h_flange]); + + // screw support + translate([d_o_bot / 2 - 0.2, 0, 9.2 / 2]) + rotate([0, -90, 0]) cylinder(h = 1, d = 9.2, center = true); + + translate([d_o_bot / 2 - 0.7, -9.2 / 2, 9.2 / 2]) + cube([1, 9.2, h_bot]); + + } + + // Cut out the inner hole for mounting + translate([0, 0, 13]) + cylinder(h = 26.02, d = d_i, center = true); + + translate([0, 0, 27]) + cylinder(h = 2, d1 = d_i, d2 = 8.4, center = true); + + translate([0, 0, 27 + (h_full - 27)/2]) + cylinder(h = 1 + h_full - 27, d = 8.4, center = true); + + // Cut out the screw hole + translate([d_o_bot / 2 - 0.2, 0, 9.2 / 2]) + rotate([0, -90, 0]) cylinder(h = d_o_bot + 1, d = 4.6, center = true); + + // Cut off the top (flatten the dome) + translate([0, 0, h_bot + h_neck + h_top + h_dome+ 2]) cube([d_o_top, d_o_top, 4], center = true); + + // Cut off the flange at an angle + translate([0, d_i/2 + 9, 0]) + rotate([33.18, 0, 0]) + translate([-(w_flange + 0.2) / 2, 0, -10]) + cube([w_flange + 0.2, h_flange + 0.2, 10]); +} diff --git a/replacement-parts/bathroom-fan-vent-clip.scad b/replacement-parts/bathroom-fan-vent-clip.scad new file mode 100644 index 0000000..34ed021 --- /dev/null +++ b/replacement-parts/bathroom-fan-vent-clip.scad @@ -0,0 +1,36 @@ +$fn=36; + +ep = 0.01; +height = 4.5; + +iDepth = 3.5; +oDepth = 9; + +iWidth = 13; +oWidth = 20; + +clipWidth=5; + +overhang=5; + +pinClear = 2.2; // pin clearance +slideClear = 1.8; + +union() { + // base bracket + difference() { + translate([-oWidth/2, 0, 0]) cube([oWidth, oDepth, height + ep]); + + translate([-iWidth/2, -ep, -ep]) cube([iWidth, iDepth + ep, height + 3*ep]); + } + + // clip + difference() { + translate([-clipWidth/2, -overhang, height]) cube([clipWidth, oDepth + overhang, 4]); + + color("red") union() { + translate([-oWidth/2, -2.5, height + 1.25]) rotate([0, 90, 0]) cylinder(d=3, h=oWidth); + translate([-clipWidth/2 - ep, -overhang - ep, height - ep]) cube([clipWidth + 2*ep, overhang + ep, 1.5 + ep]); + } + } +} diff --git a/replacement-parts/elijah-black-shelf-supports.scad b/replacement-parts/elijah-black-shelf-supports.scad new file mode 100644 index 0000000..5fb1672 --- /dev/null +++ b/replacement-parts/elijah-black-shelf-supports.scad @@ -0,0 +1,82 @@ +// all measurements in mm +$fn=128; + +// Version History +// 1 - id=25.6, od1=31, od2=29, h=44, tabHeight=13, tabClearance=0.4 +// 2 - id=27, od1=31, od2=29, h=44, tabHeight=13, tabClearance=0.1 +// 3 - id=27, od1=31, od2=29, h=44, tabHeight=13, tabClearance=0 +// 4 - id=26, od1=31, od2=29, h=44, tabHeight=13, tabClearance=0 +// 5 - id=26, od1=31, od2=29, h=44, tabHeight=13, tabClearance=-0.1, angle in tab +version = "5"; + +id = 26; +od1 = 31; +od2 = 29; +h = 44; +tabClearance = -0.1; +tabHeight = 13; + +module tab() { + translate([id/2 + 0.2, 0, -6.5]) rotate([0, 0, 7]) difference() { + // tab + translate([0, -0.01, 0]) cube([1.6, 4.01, tabHeight]); + // tab chamfers + union() { + translate([0 - 0.2, 2, 0]) rotate([-75, 0, 0]) cube([2, 4, 4]); + translate([0 - 0.2, 2, tabHeight]) mirror([0, 0, 1]) rotate([-75, 0, 0]) cube([2, 4, 4]); + } + } +} + +module tabCutout() { + translate([-id/2 - 3, -5, -(tabHeight + tabClearance)/2]) cube([6, 5.01, tabHeight + tabClearance]); +} + +module catchRing() { + translate([0, 0, 9]) difference() { + cylinder(h=0.8, d=od2, center = true); + translate([0, 0, -0.05]) cylinder(h=1, d=id - 0.8, center = true); + } +} + +module mainCylinderBody() { + difference() { + union() { + difference() { + // outer cylinder + cylinder(h=h, d1=od1, d2=od2, center = true); + + // cylinder bore and top chamfer + union() { + // inner bore + translate([0, 0, -0.01]) cylinder(h=h + 0.1, d=id, center = true); + + // top chamfer + translate([0, 0, h/2-0.02]) difference() { + cylinder(h=2.2, d1=od1+3, d2=od2+3, center = true); + translate([0, 0, -0.01]) cylinder(h=2.24, d1=od2+0.1, d2=id-0.2, center = true); + } + } + } + + catchRing(); + } + // cutout half + translate([-(od2+4)/2, 0, -h/2 - 1]) cube([od1 + 4, od1, h + 2]); + } +} + + +difference() { + union() { + mainCylinderBody(); + tab(); + } + + union() { + tabCutout(); + translate([0, -0.2-id/2, 4-h/2]) rotate([90, 0, 180]) + linear_extrude(0.8) + text(str("v", version), size=6, halign="center", valign="center", font="Iosevka"); + } +} diff --git a/replacement-parts/keycaps/ctrl-key.scad b/replacement-parts/keycaps/ctrl-key.scad index 646bd89..fdf7434 100644 --- a/replacement-parts/keycaps/ctrl-key.scad +++ b/replacement-parts/keycaps/ctrl-key.scad @@ -1,11 +1,11 @@ $fn=180; ow=23; // outer width od=18; // outer depth -oh=10; // outer height +oh=10; // outer height ep = 0.01; iw=17.4; // inner width -id=12.5; // inner depth +id=12.5; // inner depth ih=7.6; // inner height sphMul = 4; @@ -51,6 +51,10 @@ difference() { ct = 1.3; // cross thickness // inner cylinder + // there are conflicting constraints here: the diameter needs to be thick + // enough to have strong walls, particularly at the points where the + // cross cutaway comes close to them, but the whole cylinder also needs + // to fit into the recess allowed in the keypost color("DimGray") translate([ow/2, od/2, 1.4]) cylinder(d=5.3, h=ih - 1.4); // inner cross recess (post hole) diff --git a/woodworking/furniture/office-shelving.scad b/woodworking/furniture/office-shelving.scad new file mode 100644 index 0000000..a033e35 --- /dev/null +++ b/woodworking/furniture/office-shelving.scad @@ -0,0 +1,65 @@ +// measurements in inches +width = 40; +height = 99.5; +depth = 19.5; + +cubeSize = 13.5; + +shelfThickness = 0.5; +wallThickness = 1; + +module shelvingUnit(includeFitTest = false) { + color("#242424") union() { + // sides + cube([wallThickness, depth, height]); + translate([width - wallThickness, 0, 0]) cube([wallThickness, depth, height]); + + // top and bottom + cube([width, depth, wallThickness]); + translate([0, 0, height - wallThickness]) cube([width, depth, wallThickness]); + } + + color("#384048") union() { + // shelves + for (i = [1 : floor((height - 2 * wallThickness) / (cubeSize + wallThickness))]) { + translate([wallThickness, 0, i*cubeSize + (i-1)*shelfThickness + wallThickness]) + cube([width - 2 * wallThickness, depth, shelfThickness]); + } + + // dividers + for (i = [1 : floor((width - 2 * wallThickness) / (cubeSize + wallThickness))]) { + translate([i * (cubeSize + wallThickness), 0, wallThickness]) + cube([wallThickness, depth, height - 2 * wallThickness]); + } + } + + if (includeFitTest) { + // test box fits + color("CornflowerBlue") union() { + // main boxes + translate([wallThickness, 0.01, wallThickness]) + for (i = [0 : floor((height - 2 * wallThickness) / (cubeSize + wallThickness))]) + for (j = [0 : floor((width - 2 * wallThickness) / (cubeSize + wallThickness)) - 1]) + translate([j * (cubeSize + wallThickness), 0, i * (cubeSize + shelfThickness)]) + cube([cubeSize, depth, cubeSize]); + + // corner box + translate([30, 0.01, wallThickness]) + for (i = [0 : floor((height - 2 * wallThickness) / (cubeSize + wallThickness))]) + translate([0, 0, i * (cubeSize + shelfThickness)]) cube([9, depth, cubeSize]); + } + } +} + +difference() { + shelvingUnit(); + + // cutout for corner box + union() { + translate([39, depth + 0.01, -1]) rotate([0, 0, 180]) difference() { + cube([9, depth - wallThickness, height + 2]); + translate([9, 0, -1]) rotate([0, 0, atan(9 / (depth - 2*wallThickness))]) cube([9, depth*2, height + 4]); + } + translate([width - wallThickness - 0.1, -0.1, -0.1]) cube([wallThickness + 0.2, depth + 0.2, height + 0.2]); + } +}