Kallax organization models.
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
include <./insert-box.scad>;
|
||||||
|
|
||||||
|
$fn=64;
|
||||||
|
dowelDiameter = 12.7; // 0.5 inch
|
||||||
|
module dowel() {
|
||||||
|
color("Sienna") rotate([0, 90, ])
|
||||||
|
cylinder(h=innerSide, d=dowelDiameter, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
outerBox();
|
||||||
|
supportingFelt();
|
||||||
|
|
||||||
|
translate([feltThickness + boardThickness, 0, feltThickness + boardThickness])
|
||||||
|
union() {
|
||||||
|
// Everything within this union is referenced off of the inner box. The outer
|
||||||
|
// translate accounts for the felt and walls.
|
||||||
|
|
||||||
|
translate([innerSide/2, 0, innerSide - dowelDiameter*1.5]) // center dowels on X, raise Z
|
||||||
|
union() {
|
||||||
|
translate([0, kallaxDepth*0.25, 0]) dowel();
|
||||||
|
translate([0, kallaxDepth*0.75, 0]) dowel();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
dowelDiameter = 12.7; // 1/2 inch in mm
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
$fn = 32;
|
||||||
|
|
||||||
|
l = 76;
|
||||||
|
w = 50;
|
||||||
|
th = 1;
|
||||||
|
|
||||||
|
color("black") cube([l, w, th], center=true);
|
||||||
|
// color("white") translate([0, 0, th]) linear_extrude(0.2) text("Ethernet", font="monofur", halign="center", valign="center",size=12);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
kallaxSide = 335; // Full width of a Kallax shelf
|
||||||
|
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)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
include <./constants.scad>;
|
||||||
|
|
||||||
|
boardThickness = 6.4;
|
||||||
|
feltThickness = 2.4;
|
||||||
|
feltWidth = 12;
|
||||||
|
innerSide = kallaxSide - 2 * (feltThickness + boardThickness);
|
||||||
|
|
||||||
|
module feltStrip() {
|
||||||
|
color("DimGray") cube([feltThickness, kallaxDepth, feltWidth]);
|
||||||
|
}
|
||||||
|
|
||||||
|
module sideBoard() {
|
||||||
|
difference() {
|
||||||
|
color ("BurlyWood") cube([boardThickness, kallaxDepth, kallaxSide - 2*feltThickness]);
|
||||||
|
color("black") translate([0.2, 100, 30]) rotate([90, 0, -90]) linear_extrude(0.3)
|
||||||
|
text(font="Iosevka", size=16, halign="center", valign="center", "side - plywood");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module horizontalBoard() {
|
||||||
|
difference() {
|
||||||
|
color ("Wheat") cube([innerSide, kallaxDepth, boardThickness]);
|
||||||
|
color("black") translate([110, 30, boardThickness - 0.2]) rotate([0, 0, 0]) linear_extrude(0.3)
|
||||||
|
text(font="Iosevka", size=16, halign="center", valign="center", "top/bot - plywood");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module outerBox() {
|
||||||
|
translate([feltThickness, 0, feltThickness]) union() {
|
||||||
|
// left and right side boards
|
||||||
|
translate([0, 0, 0]) sideBoard();
|
||||||
|
translate([innerSide + boardThickness , 0, 0]) sideBoard();
|
||||||
|
|
||||||
|
// top and bottom horizontal boards
|
||||||
|
translate([boardThickness, 0, 0]) horizontalBoard();
|
||||||
|
translate([boardThickness, 0, innerSide + boardThickness]) horizontalBoard();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module supportingFelt() {
|
||||||
|
// felt strips for the left side
|
||||||
|
translate([0, 0, feltThickness + 20]) feltStrip();
|
||||||
|
translate([0, 0, (innerSide - feltThickness)/2]) feltStrip();
|
||||||
|
translate([0, 0, feltThickness + innerSide - feltWidth - 20]) feltStrip();
|
||||||
|
|
||||||
|
// felt strips for the right side
|
||||||
|
translate([innerSide + feltThickness + 2*boardThickness, 0, feltThickness + 20]) feltStrip();
|
||||||
|
translate([innerSide + feltThickness + 2*boardThickness, 0, (innerSide - feltThickness)/2]) feltStrip();
|
||||||
|
translate([innerSide + feltThickness + 2*boardThickness, 0, feltThickness + innerSide - feltWidth - 20]) feltStrip();
|
||||||
|
|
||||||
|
// felt strips for the top
|
||||||
|
translate([feltWidth + boardThickness + 20, 0, 0]) rotate([0, -90, 0]) feltStrip();
|
||||||
|
translate([(kallaxSide - feltWidth)/2, 0, 0]) rotate([0, -90, 0]) feltStrip();
|
||||||
|
translate([kallaxSide - feltWidth - 20, 0, 0]) rotate([0, -90, 0]) feltStrip();
|
||||||
|
|
||||||
|
// felt strips for the bottom
|
||||||
|
translate([feltWidth + 20, 0, kallaxSide - feltThickness]) rotate([0, -90, 0]) feltStrip();
|
||||||
|
translate([(kallaxSide - feltWidth)/2, 0, kallaxSide - feltThickness]) rotate([0, -90, 0]) feltStrip();
|
||||||
|
translate([kallaxSide - feltWidth - 20, 0, kallaxSide - feltThickness]) rotate([0, -90, 0]) feltStrip();
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
include <./constants.scad>
|
||||||
|
|
||||||
|
// all measurements in mm
|
||||||
|
boardThickness = 4.7; // 1/8" plywood
|
||||||
|
feltThickness = 2.5;
|
||||||
|
clipThickness = boardThickness + 2*feltThickness;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
module customSupport() {
|
||||||
|
// 45-degree supports
|
||||||
|
difference() {
|
||||||
|
translate([clipThickness/2, -clipThickness/2, 0])
|
||||||
|
cube([1, clipThickness, clipThickness - 2]);
|
||||||
|
|
||||||
|
rotate([45, 0, 0])
|
||||||
|
translate([0, -0.1, -0.1])
|
||||||
|
cube([clipThickness, clipThickness, clipThickness]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module cornerClip() {
|
||||||
|
difference() {
|
||||||
|
cube([clipThickness, clipThickness, clipThickness]);
|
||||||
|
|
||||||
|
translate([feltThickness, feltThickness, feltThickness])
|
||||||
|
cube([boardThickness, clipThickness, clipThickness]);
|
||||||
|
|
||||||
|
translate([feltThickness, feltThickness, feltThickness])
|
||||||
|
cube([clipThickness, boardThickness, clipThickness]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 crossClip() {
|
||||||
|
difference() {
|
||||||
|
cube([2 * clipThickness, clipThickness, clipThickness]);
|
||||||
|
|
||||||
|
translate([-0.1, feltThickness, feltThickness])
|
||||||
|
cube([2 * clipThickness + 0.2, boardThickness, clipThickness]);
|
||||||
|
|
||||||
|
translate([clipThickness - boardThickness/2, -0.1, feltThickness])
|
||||||
|
cube([boardThickness, clipThickness + 0.2, clipThickness]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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), 5 * clipThickness, 0])
|
||||||
|
rotate([45, 0, 0])
|
||||||
|
crossClip();
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([-1, -1, -1.4]) cube([100, 100, 1.4]);
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
// Create a tenon with chamfered edges on the front face. The tenon is facing
|
||||||
|
// the positive Y direction. It is offset by -0.01 in Y to make it easy to
|
||||||
|
// ensure that it intersects with the main body it is attached to.
|
||||||
|
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.1, dims[2] - 1.1]) rotate([45, 0, 0]) cube([dims[0] + 1, 2, 2]);
|
||||||
|
translate([-0.5, dims[1] + 0.1, -1.7]) rotate([45, 0, 0]) 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 = 0) {
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the tail of a dovetail for a dovetail joint. The tail is oriented in
|
||||||
|
// the positive Y direction. It is exactly (tailHeight + 0.01) tall (in the Y
|
||||||
|
// direction) and positioned so that its base is at Y=-0.01 to make it easy to
|
||||||
|
// overlap with the main body it is attached to.
|
||||||
|
module dovetail(tailHeight, tailWidthMin, tailWidthMax, depth) {
|
||||||
|
angle = atan((tailWidthMax - tailWidthMin) / (2 * tailHeight));
|
||||||
|
|
||||||
|
translate([0, tailHeight, 0])
|
||||||
|
mirror([0, 1, 0])
|
||||||
|
difference() {
|
||||||
|
cube([tailWidthMax, tailHeight + 0.01, depth + 0.01]);
|
||||||
|
color("blue") translate([tailWidthMax, 0, -0.1]) rotate([0, 0, angle]) cube([tailWidthMax, tailHeight*2, depth+0.2]);
|
||||||
|
color("blue") rotate([0, 0, -angle]) translate([-tailWidthMax, 0, -0.1]) cube([tailWidthMax, tailHeight*2, depth+0.2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
module prism(l, w, h) {
|
||||||
|
polyhedron(// pt 0 1 2 3 4 5
|
||||||
|
points=[[0,0,0], [0,w,h], [l,w,h], [l,0,0], [0,w,0], [l,w,0]],
|
||||||
|
// top sloping face (A)
|
||||||
|
faces=[[0,1,2,3],
|
||||||
|
// vertical rectangular face (B)
|
||||||
|
[2,1,4,5],
|
||||||
|
// bottom face (C)
|
||||||
|
[0,3,5,4],
|
||||||
|
// rear triangular face (D)
|
||||||
|
[0,4,1],
|
||||||
|
// front triangular face (E)
|
||||||
|
[3,2,5]]
|
||||||
|
);}
|
||||||
Reference in New Issue
Block a user