$fn=64; // --- Parameters --- // Total width of the stand stand_width = 240; // Total depth of the stand stand_depth = 130; // Height at the front edge height_front = 50; // Height at the back edge (creates the ergonomic tilt) height_back = 80; // Radius of the outer corners corner_radius = 15; // Wall thickness for the hollow shell and bowl tubes wall_thickness = 3; // Diameter of the cutouts for the bowls bowl_diameter = 100; // Calculated angle for the top slope tilt_angle = atan2(height_back - height_front, stand_depth); // --- Modules --- module rounded_rect(w, d, r) { hull() { translate([r, r]) circle(r); translate([w-r, r]) circle(r); translate([r, d-r]) circle(r); translate([w-r, d-r]) circle(r); } } module main_solid() { intersection() { // Base extrusion linear_extrude(height = height_back + 20) rounded_rect(stand_width, stand_depth, corner_radius); // Angled cutter for the top surface translate([0, 0, height_front]) rotate([-tilt_angle, 0, 0]) translate([-50, -50, 0]) cube([stand_width + 100, stand_depth + 100, height_back + 50]); } } module inner_void() { difference() { // The hollow interior space intersection() { translate([0, 0, -1]) linear_extrude(height = height_back + 20) translate([wall_thickness, wall_thickness]) rounded_rect( stand_width - 2*wall_thickness, stand_depth - 2*wall_thickness, max(1, corner_radius - wall_thickness) ); // Angled cutter for the inner roof translate([0, 0, height_front - wall_thickness]) rotate([-tilt_angle, 0, 0]) translate([-50, -50, 0]) cube([stand_width + 100, stand_depth + 100, height_back + 50]); } // Exclude the bowl tubes so they remain solid walls extending to the floor for(x = [stand_width/4, 3*stand_width/4]) { translate([x, stand_depth/2, height_front + (height_back-height_front)/2]) rotate([-tilt_angle, 0, 0]) translate([0, 0, -200]) cylinder(d=bowl_diameter + 2*wall_thickness, h=400); } } } module bowl_holes() { // Cutouts for the bowls, perpendicular to the tilted surface for(x = [stand_width/4, 3*stand_width/4]) { translate([x, stand_depth/2, height_front + (height_back-height_front)/2]) rotate([-tilt_angle, 0, 0]) translate([0, 0, -200]) cylinder(d=bowl_diameter, h=400); } } // --- Main Assembly --- // Subtract the hollow interior and the bowl holes from the main solid block difference() { main_solid(); inner_void(); bowl_holes(); }