$fn=64; // --- Parametric Dimensions --- // Trellis Body trellis_width = 120; trellis_height = 180; trellis_thickness = 4; frame_width = 6; // Diamond Grid grid_spacing = 22; grid_thickness = 2.5; // Pot Rim Clips pot_rim_thickness = 4.5; // Adjust based on your pot's rim width clip_depth = 20; clip_thickness = 4; // Wall thickness of the clips clip_spacing = 70; // Distance between the two clips // --- Modules --- // Generates the main arch shape for the trellis module arch_2d(shrink=0) { offset(r=-shrink) hull() { // Top rounded arch translate([0, trellis_height - trellis_width/2]) circle(d=trellis_width); // Bottom left corner translate([-trellis_width/2 + 5, 5]) circle(r=5); // Bottom right corner translate([trellis_width/2 - 5, 5]) circle(r=5); } } // Generates a single downward-facing clip module clip() { clip_w = pot_rim_thickness + (clip_thickness * 2); difference() { // Outer clip body translate([0, -clip_depth/2 + 1]) square([clip_w, clip_depth + 2], center=true); // Inner slot for the pot rim translate([0, -clip_depth/2 - 2]) square([pot_rim_thickness, clip_depth], center=true); // Flared opening to easily slide onto the rim translate([0, -clip_depth]) polygon([ [-pot_rim_thickness/2, 0.1], [pot_rim_thickness/2, 0.1], [pot_rim_thickness/2 + clip_thickness, -clip_thickness], [-pot_rim_thickness/2 - clip_thickness, -clip_thickness] ]); } } // --- Main Assembly --- linear_extrude(trellis_thickness) { union() { // 1. Outer Frame difference() { arch_2d(0); arch_2d(frame_width); } // 2. Diamond Lattice Grid intersection() { // Embed grid slightly into the frame for a strong, clean union arch_2d(frame_width/2); union() { for(i = [-trellis_width*1.5 : grid_spacing : trellis_width*1.5]) { translate([i, 0]) rotate(45) square([grid_thickness, trellis_height*3], center=true); translate([i, 0]) rotate(-45) square([grid_thickness, trellis_height*3], center=true); } } } // 3. Solid Base Crossbar translate([0, frame_width/2]) square([trellis_width, frame_width], center=true); // 4. Pot Mounting Clips translate([-clip_spacing/2, 0]) clip(); translate([clip_spacing/2, 0]) clip(); } }