$fn=64; // --- Parameters --- cols = 4; rows = 3; cell_pitch = 40; cell_bottom_width = 30; cell_top_width = 41.5; cell_depth = 45; wall_thickness = 1.5; lip_width = 2; lip_height = 3; drain_hole_dia = 8; channel_width = 6; channel_depth = 3; // --- Main Assembly --- translate([-(cols-1)*cell_pitch/2, -(rows-1)*cell_pitch/2, 0]) tray(); // --- Modules --- module tray() { difference() { union() { // Main cell bodies for(x=[0:cols-1], y=[0:rows-1]) { translate([x*cell_pitch, y*cell_pitch, 0]) tapered_cell(cell_top_width, cell_bottom_width, cell_depth, 0); } // Outer reinforced lip translate([-cell_pitch/2 - lip_width, -cell_pitch/2 - lip_width, cell_depth - lip_height]) cube([cols*cell_pitch + 2*lip_width, rows*cell_pitch + 2*lip_width, lip_height]); } // Cell inner voids for(x=[0:cols-1], y=[0:rows-1]) { inner_top = cell_top_width - 2*wall_thickness; inner_bot = cell_bottom_width - 2*wall_thickness; translate([x*cell_pitch, y*cell_pitch, wall_thickness]) tapered_cell(inner_top, inner_bot, cell_depth, 1); // Drainage holes translate([x*cell_pitch, y*cell_pitch, -1]) cylinder(h=wall_thickness+2, d=drain_hole_dia); } // Interconnected water channels (Bottom grooves) // X-axis channels for(y=[0:rows-1]) { translate([-cell_pitch, y*cell_pitch - channel_width/2, -0.1]) cube([cols*cell_pitch + cell_pitch, channel_width, channel_depth + 0.1]); } // Y-axis channels for(x=[0:cols-1]) { translate([x*cell_pitch - channel_width/2, -cell_pitch, -0.1]) cube([channel_width, rows*cell_pitch + cell_pitch, channel_depth + 0.1]); } } } module tapered_cell(top_w, bot_w, h, extra) { hull() { translate([0, 0, -extra]) cube([bot_w, bot_w, 0.01], center=true); translate([0, 0, h + extra]) cube([top_w, top_w, 0.01], center=true); } }