// ----------------------------------------------------------------------- // Modular LED Matrix Outer Frame / Diffuser Clamp (Through-Holes) // ----------------------------------------------------------------------- // 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] // --- Matrix Parameters --- cellsX = 16; cellsY = 16; pitch = 10; borderWidth = 10; // --- Frame Settings --- thickness = 3; overhang = 1; // 1mm bite inwards to clamp the diffuser without blocking LEDs overW = borderWidth + overhang; // Total width of the frame bars lap_len = 6; // Length of the hidden half-lap joint tol = 0.2; // 0.2mm tolerance for a friction fit without sanding // --- Logic --- 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; gridWidth = cellsX * pitch; gridHeight = cellsY * pitch; leftOffset = hasLeft * borderWidth; bottomOffset = hasBottom * borderWidth; totalWidth = gridWidth + (hasLeft * borderWidth) + (hasRight * borderWidth); totalHeight = gridHeight + (hasTop * borderWidth) + (hasBottom * borderWidth); $fn = 32; // --- Countersunk Hole Module --- module cs_hole(x, y) { // M3 shaft clearance (3.2mm diameter) translate([x, y, -0.1]) cylinder(h=thickness + 0.2, r=1.6); // Countersink cone for 5mm head (using 5.2mm for flush fit) // 1mm depth matches standard 90-degree profile for this head size translate([x, y, thickness - 1]) cylinder(h=1.1, r1=1.6, r2=2.6); } difference() { union() { // Base Perimeter Bars if(hasLeft) translate([0, 0, 0]) cube([overW, totalHeight, thickness]); if(hasRight) translate([totalWidth - overW, 0, 0]) cube([overW, totalHeight, thickness]); if(hasTop) translate([0, totalHeight - overW, 0]) cube([totalWidth, overW, thickness]); if(hasBottom) translate([0, 0, 0]) cube([totalWidth, overW, thickness]); // Male Half-Lap Tabs (Hidden on the bottom half, Z = 0 to thickness/2) // Extending Right (P1, P2) on Top Bar if(hasTop && !hasRight) translate([totalWidth, totalHeight - overW, 0]) cube([lap_len, overW, thickness/2]); // Extending Right (P4, P5) on Bottom Bar if(hasBottom && !hasRight) translate([totalWidth, 0, 0]) cube([lap_len, overW, thickness/2]); // Extending Down (P1) on Left Bar if(hasLeft && !hasBottom) translate([0, -lap_len, 0]) cube([overW, lap_len, thickness/2]); // Extending Down (P3) on Right Bar if(hasRight && !hasBottom) translate([totalWidth - overW, -lap_len, 0]) cube([overW, lap_len, thickness/2]); } // Female Half-Lap Slots (Cut from Z = -0.1 to thickness/2 + tol) // Cut from Left (P2, P3) on Top Bar if(hasTop && !hasLeft) translate([-0.1, totalHeight - overW - tol, -0.1]) cube([lap_len + 0.1, overW + 2*tol, thickness/2 + tol]); // Cut from Left (P5, P6) on Bottom Bar if(hasBottom && !hasLeft) translate([-0.1, -tol, -0.1]) cube([lap_len + 0.1, overW + 2*tol, thickness/2 + tol]); // Cut from Top (P4) on Left Bar if(hasLeft && !hasTop) translate([-tol, totalHeight - lap_len, -0.1]) cube([overW + 2*tol, lap_len + 0.1, thickness/2 + tol]); // Cut from Top (P6) on Right Bar if(hasRight && !hasTop) translate([totalWidth - overW - tol, totalHeight - lap_len, -0.1]) cube([overW + 2*tol, lap_len + 0.1, thickness/2 + tol]); // Countersunk Mounting Holes // Left Border if (hasLeft) { for (i = [1 : 3]) { cs_hole(borderWidth / 2, bottomOffset + (i * gridHeight/4)); } } // Right Border if (hasRight) { for (i = [1 : 3]) { cs_hole(totalWidth - (borderWidth / 2), bottomOffset + (i * gridHeight/4)); } } // Top Border if (hasTop) { for (i = [1 : 3]) { cs_hole(leftOffset + (i * gridWidth/4), totalHeight - (borderWidth / 2)); } } // Bottom Border if (hasBottom) { for (i = [1 : 3]) { cs_hole(leftOffset + (i * gridWidth/4), borderWidth / 2); } } }