$fn = 64; // --- Parameters --- pot_inner_diameter = 100; // Inner diameter of the pot rim rim_thickness = 5; // Thickness of the pot rim clip_depth = 12; // How far the clip extends down into the pot fence_height = 35; // Height of the picket fence fence_thickness = 2; // Base thickness of the fence components num_pickets = 36; // Total number of pickets around the rim // --- Derived Variables --- r_inner = pot_inner_diameter / 2; t = fence_thickness; r_outer = r_inner + rim_thickness + t; // --- Modules --- // The inverted U-channel that clips onto the pot rim module pot_clip() { rotate_extrude() { // Inner lip (inside the pot) translate([r_inner, -clip_depth, 0]) square([t, clip_depth + t]); // Top resting surface translate([r_inner, 0, 0]) square([rim_thickness + t*2, t]); // Outer lip (base for the fence) translate([r_outer, -clip_depth, 0]) square([t, clip_depth + t]); } } // Horizontal rails connecting the pickets module rail(z_offset) { translate([0, 0, z_offset]) rotate_extrude() { // Overlap by 0.5mm for manifold geometry translate([r_outer + t - 0.5, 0, 0]) square([t, t]); } } // Individual picket or post module picket(is_post) { w = is_post ? 6 : 4; h = is_post ? fence_height + 6 : fence_height; p_thick = t + 1; // Pickets protrude slightly past rails for texture // Base rectangular shaft translate([-w/2, -0.5, 0]) cube([w, p_thick, h - w/2]); // Decorative top (sphere for posts, rounded for pickets) if (is_post) { translate([0, p_thick/2 - 0.5, h - w/2]) sphere(d=w + 2); } else { translate([0, p_thick/2 - 0.5, h - w/2]) rotate([90, 0, 0]) cylinder(h=p_thick, d=w, center=true); } } // --- Assembly --- union() { pot_clip(); // Lower and upper rails rail(8); rail(fence_height - 12); // Radial placement of pickets for (i = [0 : num_pickets - 1]) { angle = i * (360 / num_pickets); is_post = i % 4 == 0; // Every 4th picket is a thicker post rotate([0, 0, angle]) translate([r_outer + t, 0, 0]) picket(is_post); } }