// ----------------------------------------------------------------------- // Modular 6-Part Enclosure for 10mm Pitch LED Matrix WITH DOVETAILS // ----------------------------------------------------------------------- // NATIVE LANDSCAPE LAYOUT (3 columns x 2 rows) // Select which tile to generate: // 1 = Top Left | 2 = Top Mid | 3 = Top Right // 4 = Bottom Left | 5 = Bottom Mid | 6 = Bottom Right part = 1; // [1:6] // --- Core Math --- cellsX = 16; cellsY = 16; pitch = 10; gridWidth = cellsX * pitch; gridHeight = cellsY * pitch; borderWidth = 10; // Internal depth is 51mm (clearing the 49mm box height) depth = 55; wall = 4; // Logic for 3x2 Landscape Grid hasLeft = (part == 1 || part == 4) ? 1 : 0; hasRight = (part == 3 || part == 6) ? 1 : 0; hasTop = (part == 1 || part == 2 || part == 3) ? 1 : 0; hasBottom = (part == 4 || part == 5 || part == 6) ? 1 : 0; leftOffset = hasLeft * borderWidth; bottomOffset = hasBottom * borderWidth; totalWidth = gridWidth + (hasLeft * borderWidth) + (hasRight * borderWidth); totalHeight = gridHeight + (hasTop * borderWidth) + (hasBottom * borderWidth); $fn = 24; // --- Dovetail Joint Geometry --- module dovetail(clearance=0) { linear_extrude(wall) polygon([ [-0.1, -6 - clearance], [8, -10 - clearance], [8, 10 + clearance], [-0.1, 6 + clearance] ]); } module posts() { holeRad = 1.4; // Sized for M3 self-tapping screws postRad = 4; // Left Border if (hasLeft) { for (i = [1 : 3]) { translate([borderWidth / 2, bottomOffset + (i * gridHeight/4), 0]) difference() { cylinder(h=depth, r=postRad); translate([0, 0, wall]) cylinder(h=depth, r=holeRad); } } } // Right Border if (hasRight) { for (i = [1 : 3]) { translate([totalWidth - (borderWidth / 2), bottomOffset + (i * gridHeight/4), 0]) difference() { cylinder(h=depth, r=postRad); translate([0, 0, wall]) cylinder(h=depth, r=holeRad); } } } // Top Border if (hasTop) { for (i = [1 : 3]) { translate([leftOffset + (i * gridWidth/4), totalHeight - (borderWidth / 2), 0]) difference() { cylinder(h=depth, r=postRad); translate([0, 0, wall]) cylinder(h=depth, r=holeRad); } } } // Bottom Border if (hasBottom) { for (i = [1 : 3]) { translate([leftOffset + (i * gridWidth/4), borderWidth / 2, 0]) difference() { cylinder(h=depth, r=postRad); translate([0, 0, wall]) cylinder(h=depth, r=holeRad); } } } } module keyhole() { cylinder(r=4, h=wall+2, center=true); translate([0, 6, 0]) cylinder(r=2.2, h=wall+2, center=true); translate([0, 3, 0]) cube([4.4, 6, wall+2], center=true); } difference() { union() { // Main block cube([totalWidth, totalHeight, depth]); // Add Male Dovetail Tabs on internal edges if (!hasRight) { for(i=[1:3]) translate([totalWidth, totalHeight * 0.25 * i, 0]) dovetail(0); } if (!hasBottom) { for(i=[1:3]) translate([totalWidth * 0.25 * i, 0, 0]) rotate([0, 0, -90]) dovetail(0); } } // Cavity cutout cutX = hasLeft ? wall : -1; cutY = hasBottom ? wall : -1; cutW = totalWidth - (hasLeft ? wall : -1) - (hasRight ? wall : -1); cutH = totalHeight - (hasBottom ? wall : -1) - (hasTop ? wall : -1); translate([cutX, cutY, wall]) cube([cutW, cutH, depth]); // Subtract Female Dovetail Cuts on internal edges if (!hasLeft) { for(i=[1:3]) translate([0, totalHeight * 0.25 * i, 0]) dovetail(0.3); } if (!hasTop) { for(i=[1:3]) translate([totalWidth * 0.25 * i, totalHeight, 0]) rotate([0, 0, -90]) dovetail(0.3); } // Power Jack (9mm hole) straight through the right wall if (part == 6) { // Y = 17.5 (slot start) + 12.5 (center of 25mm controller) = 30 // Z = 4 (floor) + 19 = 23 translate([totalWidth + 1, 30, 23]) rotate([0, -90, 0]) cylinder(h=wall + 20, r=4.5); } // Wall mount keyholes on top parts if (hasTop && hasLeft) { translate([totalWidth/2, totalHeight/2, wall/2]) keyhole(); } if (hasTop && hasRight) { translate([totalWidth/2, totalHeight/2, wall/2]) keyhole(); } } // Add mounting posts back into the cavity posts(); // ================================================================= // PERPENDICULAR CONTROLLER SLOT // Exclusively generated on Part 6. // Mounts the 25x49 face dead flush against the internal right wall. // Controller extends 90mm inward along the X-axis. // ================================================================= if (part == 6) { // Left retaining wall (X-axis inner stop at 90mm length) translate([73, 15.5, wall]) cube([2, 30, 20]); // Top retaining wall (Y-axis upper stop) translate([73, 43.5, wall]) cube([93, 2, 20]); // Bottom retaining wall (Y-axis lower stop) translate([73, 15.5, wall]) cube([93, 2, 20]); }