$fn = 64; // --- Parameters --- num_slots = 6; slot_diameter = 12; slot_spacing = 20; opening_width = 9; // Slightly smaller than slot_diameter for a snap-in fit holder_width = num_slots * slot_spacing; holder_depth = 30; holder_height = 20; // Dovetail parameters (ArtArsenal style rail mount) dt_base = 16; dt_neck = 10; dt_depth = 5; // --- Modules --- module dovetail() { linear_extrude(height = holder_height) polygon(points=[ [-dt_neck/2, 0], [dt_neck/2, 0], [dt_base/2, -dt_depth], [-dt_base/2, -dt_depth] ]); } module brush_holder() { union() { // Main body with U-slots difference() { // Solid base block cube([holder_width, holder_depth, holder_height]); // Cutout slots for (i = [0 : num_slots - 1]) { slot_x = (i + 0.5) * slot_spacing; slot_y = holder_depth - 12; // Center of the slot // Main circular hole translate([slot_x, slot_y, -1]) cylinder(h = holder_height + 2, d = slot_diameter); // Front opening cutout translate([slot_x - opening_width/2, slot_y, -1]) cube([opening_width, holder_depth - slot_y + 2, holder_height + 2]); } } // Mounts: Two dovetails for stability on the wall rail translate([holder_width * 0.25, 0, 0]) dovetail(); translate([holder_width * 0.75, 0, 0]) dovetail(); } } // --- Render --- // Centered on the X axis, back flush with Y=0 translate([-holder_width/2, 0, 0]) brush_holder();