$fn=64; // --- Parameters --- jar_diameter = 90; // Inner diameter for the treat jar holder_depth = 50; // Depth of the jar cup wall_thickness = 4; // Thickness of the walls rail_width = 16; // Thickness of the PetStation rail rail_height = 25; // Height of the rail hook_width = 45; // Width of the mounting hook hook_drop = 15; // Length of the hook's back prong bottom_lip = 12; // Width of the bottom lip (creates a hole to save plastic) // --- Derived Variables --- jar_od = jar_diameter + (wall_thickness * 2); bracket_z_start = holder_depth - rail_height - wall_thickness; module treat_jar_holder() { difference() { union() { // Main Cup cylinder(d=jar_od, h=holder_depth); // Rail Bracket Block (embedded into the cylinder wall) translate([-hook_width/2, jar_od/2 - wall_thickness*2, bracket_z_start]) cube([hook_width, wall_thickness*3 + rail_width, rail_height + wall_thickness]); // Support Gusset (under the bracket for strength) hull() { translate([-hook_width/2, jar_od/2 - wall_thickness*2, bracket_z_start]) cube([hook_width, wall_thickness*2, 0.1]); translate([-hook_width/2, jar_od/2 - wall_thickness*2, wall_thickness]) cube([hook_width, 0.1, 0.1]); } } // Hollow out the cup interior translate([0, 0, wall_thickness]) cylinder(d=jar_diameter, h=holder_depth + 1); // Bottom hole to save plastic and allow cleaning translate([0, 0, -1]) cylinder(d=jar_diameter - (bottom_lip * 2), h=wall_thickness + 2); // Rail Slot Cutout (opens downwards) translate([-(hook_width+2)/2, jar_od/2, bracket_z_start - 1]) cube([hook_width + 2, rail_width, rail_height + 1]); // Trim Outer Hook Prong to match desired hook_drop translate([-(hook_width+2)/2, jar_od/2 + rail_width - 0.1, -1]) cube([hook_width + 2, wall_thickness + 2, holder_depth - wall_thickness - hook_drop + 1]); } } // Render the model treat_jar_holder();