$fn = 64; // --- Parameters --- // Width of the attachment (Z-axis when printed flat) part_width = 20; // Base plate dimensions plate_thickness = 10; plate_height = 65; corner_radius = 2; // Rail cutout dimensions (French cleat style for PetStation/generic rails) rail_cut_depth = 5; rail_cut_bottom = 10; rail_cut_top = 55; rail_angle_drop = 6; // Hook dimensions hook_thickness = 12; hook_extension = 35; hook_upward = 25; hook_y_offset = 25; hook_knob_dia = 18; // --- Module --- module leash_hook() { // Extrude the 2D profile to make it 3D // Designed to print flat on its side for maximum layer adhesion and strength linear_extrude(height = part_width, center = false) { difference() { union() { // Main backplate with rounded front edges hull() { translate([0, 0]) square([0.1, plate_height]); translate([plate_thickness - corner_radius, corner_radius]) circle(r=corner_radius); translate([plate_thickness - corner_radius, plate_height - corner_radius]) circle(r=corner_radius); } // Hook horizontal shaft hull() { translate([plate_thickness - 0.1, hook_y_offset - hook_thickness/2]) square([0.1, hook_thickness]); translate([plate_thickness + hook_extension, hook_y_offset]) circle(d=hook_thickness); } // Hook upward curve hull() { translate([plate_thickness + hook_extension, hook_y_offset]) circle(d=hook_thickness); translate([plate_thickness + hook_extension, hook_y_offset + hook_upward]) circle(d=hook_thickness); } // Hook end knob to prevent leash from slipping off translate([plate_thickness + hook_extension, hook_y_offset + hook_upward]) circle(d=hook_knob_dia); } // Rail groove cutout (subtracted from the back) // Creates a downward-pointing lip to hang securely on a wall rail polygon([ [-0.1, rail_cut_bottom - 2], // Slight lead-in chamfer for easy insertion [rail_cut_depth, rail_cut_bottom], [rail_cut_depth, rail_cut_top], [-0.1, rail_cut_top - rail_angle_drop] ]); } } } // Render the part leash_hook();