$fn = 64; // --- PARAMETERS --- roll_width = 120; // Width of the paper roll roll_max_dia = 100; // Maximum diameter of the paper roll core_dia = 20; // Diameter of the roll's inner core wall_thick = 5; // Thickness of the walls // Calculated dimensions X_size = roll_width + 2 * wall_thick; Y_size = roll_max_dia + wall_thick + 10; Z_size = roll_max_dia + 30; spindle_y = wall_thick + roll_max_dia/2 + 5; spindle_z = Z_size - roll_max_dia/2 - 10; // --- MAIN ASSEMBLY --- // Printed in an orientation that requires zero supports dispenser(); spindle(); module dispenser() { union() { backplate(); left_side(); right_side(); cutter_bar(); } } module backplate() { difference() { cube([X_size, wall_thick, Z_size]); // Wall mounting holes translate([X_size/4, -1, Z_size - 20]) rotate([-90, 0, 0]) cylinder(d=5, h=wall_thick+2); translate([3*X_size/4, -1, Z_size - 20]) rotate([-90, 0, 0]) cylinder(d=5, h=wall_thick+2); translate([X_size/4, -1, 20]) rotate([-90, 0, 0]) cylinder(d=5, h=wall_thick+2); translate([3*X_size/4, -1, 20]) rotate([-90, 0, 0]) cylinder(d=5, h=wall_thick+2); } } module side_panel() { difference() { hull() { // Bottom footprint cube([wall_thick, Y_size, wall_thick]); // Back wall cube([wall_thick, wall_thick, Z_size]); // Top flat section for the spindle slot translate([0, 0, Z_size - wall_thick]) cube([wall_thick, spindle_y + 15, wall_thick]); } // U-slot for dropping in the spindle translate([-1, spindle_y, spindle_z]) { rotate([0, 90, 0]) cylinder(d=core_dia+4, h=wall_thick+2); translate([0, -(core_dia+4)/2, 0]) cube([wall_thick+2, core_dia+4, Z_size]); } } } module left_side() { side_panel(); } module right_side() { translate([X_size - wall_thick, 0, 0]) side_panel(); } module cutter_bar() { translate([0, Y_size - 15, 0]) { hull() { // Base of the cutter bar cube([X_size, 15, 2]); // Sharp cutting edge pointing up/backward translate([0, 14, wall_thick*1.5]) cube([X_size, 1, 1]); } } } module spindle() { // Placed next to the dispenser for easy print-in-place translate([X_size + 30, Y_size/2, 0]) { // Bottom flange cylinder(d=core_dia + 10, h=wall_thick); // Main shaft cylinder(d=core_dia, h=X_size + 10); // Top flange (chamfered for support-free 3D printing) translate([0, 0, X_size + 10]) cylinder(d1=core_dia, d2=core_dia + 10, h=wall_thick); translate([0, 0, X_size + 10 + wall_thick]) cylinder(d=core_dia + 10, h=wall_thick); } }