$fn = 64; // --- Parameters --- num_collars = 4; // Number of hooks for collars spacing = 55; // Distance between hooks hook_length = 35; // Length of each hook hook_dia = 12; // Diameter of the hook shaft end_cap_dia = 20; // Diameter of the end cap to prevent slipping base_height = 40; // Height of the wall plate base_thickness = 6; // Thickness of the wall plate padding = 35; // Space on ends for mounting holes corner_radius = 5; // Radius for rounded corners of the base screw_dia = 4.5; // Diameter of mounting screws screw_head_dia = 9.5; // Diameter of screw head for countersink // Calculated base width base_width = (num_collars - 1) * spacing + (padding * 2); // --- Main Assembly --- difference() { // Main body union() { rounded_base(); // Collar Hooks for (i = [0 : num_collars - 1]) { x_pos = (i - (num_collars - 1) / 2) * spacing; translate([x_pos, 0, 0]) hook(); } } // Mounting holes translate([-base_width/2 + 15, 0, 0]) screw_hole(); translate([base_width/2 - 15, 0, 0]) screw_hole(); } // --- Modules --- module rounded_base() { hull() { translate([-base_width/2 + corner_radius, -base_height/2 + corner_radius, 0]) cylinder(h=base_thickness, r=corner_radius); translate([base_width/2 - corner_radius, -base_height/2 + corner_radius, 0]) cylinder(h=base_thickness, r=corner_radius); translate([-base_width/2 + corner_radius, base_height/2 - corner_radius, 0]) cylinder(h=base_thickness, r=corner_radius); translate([base_width/2 - corner_radius, base_height/2 - corner_radius, 0]) cylinder(h=base_thickness, r=corner_radius); } } module hook() { translate([0, 0, base_thickness - 0.01]) { // Fillet at the base for strength cylinder(h=4.01, d1=hook_dia + 10, d2=hook_dia); // Main shaft cylinder(h=hook_length, d=hook_dia); // End cap (45-degree chamfers for support-free 3D printing) translate([0, 0, hook_length]) { cylinder(h=4, d1=hook_dia, d2=end_cap_dia); translate([0, 0, 4]) cylinder(h=4, d1=end_cap_dia, d2=hook_dia - 2); } } } module screw_hole() { // Screw shaft translate([0, 0, -1]) cylinder(h=base_thickness + 2, d=screw_dia); // Countersink for screw head translate([0, 0, base_thickness - 3]) cylinder(h=3.01, d1=screw_dia, d2=screw_head_dia); }