Rendering these values. This takes a few seconds.
Download STL
Read this model as text

A round grid that lies on the soil of a plant pot so a cat cannot dig in it. It has a hole in the middle for the stem, is split into 2, 3 or 4 loose segments so it fits around an existing plant and on a small print bed, and carries cone spikes on the underside that pin it into the soil.

The image shows the solid OpenSCAD renders at diameter 200 · hole_d 40 · thickness 3 · bar_w 3 · rings 4 · ring_spacing square · spokes_per_segment 4 · outer_spokes_from 2 · swirl 30 · segments 4 · gap 1 · edge_mode parallel · part all · spike_len 25 · spike_w 4 · spike_ring_step 2 · spike_spoke_step 2 · round_r 0.5 · smoothness 96 · color_grid ForestGreen.

MIT

Cat guard for plant pots

mick/plant-cat-guard@1.3.0

Remix this
Report

For a legal or policy problem: a license violation, personal data, somebody else’s work republished as their own. A model that prints badly is a comment, not a report.

Sign in to report

0reused0 remixes · 0 imports1downloads1.3.0latest

Parameters

from source
80400, steps of 5
10200, steps of 2
26, steps of 0.5
28, steps of 0.5
210, steps of 1
110, steps of 1
09, steps of 1

Showing the render for these values.

Description

What is this

A round grid that lies on the soil of a plant pot so a cat cannot dig in it. It has a hole in the middle for the stem, is split into 2, 3 or 4 loose segments so it fits around an existing plant and on a small print bed, and carries cone spikes on the underside that pin it into the soil.

What you use it for

Keeping cats (and their toilet habits) out of plant pots. Set the diameter to the pot, the hole to the stem, pick the number of segments, print each segment upside down with the spikes pointing up and press them into the soil around the plant.

Design notes

The grid is rings crossed by spokes, all drawn in 2D and extruded once. Spokes are strokes along a path, so swirl turns the straight spokes into a spiral around the stem without changing anything else. ring_spacing = "square" places the rings geometrically so every cell keeps the same proportions from hole to rim, and outer_spokes_from adds a spoke between every pair of spokes from that ring outward, dartboard style, so the outer cells do not grow wide.

The split runs along spokes: a cut spoke is drawn twice, one full bar on each side of the gap, so every segment is a closed frame. edge_mode = "parallel" shifts the two bars sideways and keeps the gap constant; "radial" rotates them so they point at the centre, which makes the gap a wedge that opens toward the rim.

Spikes are plain cones on the crossings of rings and spokes, on every n-th ring and n-th spoke. They are clipped to the outer diameter, so a spike on the rim never sticks out past the edge of the guard. Rounding is one offset pass over the finished 2D drawing, as a final polish. part = "one" gives a single segment flipped onto its plate side, the print orientation.

Parameters

diameter and hole_d size the plate, thickness and bar_w the bars. rings, ring_spacing, spokes_per_segment, outer_spokes_from and swirl set the grid. segments, gap and edge_mode control the split. part picks the whole guard or one segment. spike_len, spike_w, spike_ring_step and spike_spoke_step shape and place the spikes. round_r is the polish, color_grid the display colour.

Use with your agent
{
  "mcpServers": {
    "remixcad": {
      "type": "http",
      "url": "https://remix-cad.vercel.app/api/mcp"
    }
  }
}
get_model("mick/plant-cat-guard@1.3.0")

Returns the manifest, the source, the import closure and the license obligations. Full MCP setup.

Parameter table

Parsed from the Customizer annotations in main.scad
Parameters of Cat guard for plant pots, with the ranges the source declares
NameDefaultRangeUnitDescription
diameter20080 to 400 step 5
hole_d4010 to 200 step 2
thickness32 to 6 step 0.5
bar_w32 to 8 step 0.5
rings42 to 10 step 1
ring_spacing"square"even, square
spokes_per_segment41 to 10 step 1
outer_spokes_from20 to 9 step 1
swirl30-120 to 120 step 5
segments42, 3, 4
gap10.5 to 3 step 0.1
edge_mode"parallel"parallel, radial
part"all"all, one
spike_len250 to 60 step 1
spike_w42 to 10 step 0.5
spike_ring_step21 to 5 step 1
spike_spoke_step21 to 6 step 1
round_r0.50 to 2 step 0.25
smoothness9632 to 192 step 16
color_grid"ForestGreen"ForestGreen, Silver, Gainsboro, White, DimGray, Black, SlateGray, FireBrick, SteelBlue, Goldenrod

Lineage

0 models depend on this one

Only what this model came from and what came from it.

Remix, the code changed Import, used unchanged and pinned The version you are on Withdrawn, still recorded

License

Whoever downloads this takes these obligations along
  • mick/plant-cat-guard@1.3.0 is MIT

Source

main.scad is the entrypoint
main.scad
// A round grid that lies on the soil of a plant pot to keep cats out. Split into loose
// segments so it fits around an existing plant, with cone spikes underneath to pin it
// into the soil. Everything is drawn in 2D from circles and strokes and extruded once;
// rounding is one offset pass over the finished drawing, as a final polish.

/* [Size] */
// Outer diameter of the guard. Match it to the inside of the pot.
diameter = 200; // [80:5:400]
// Diameter of the hole in the middle, around the stem.
hole_d = 40; // [10:2:200]
// Thickness of the plate.
thickness = 3; // [2:0.5:6]
// Width of the bars.
bar_w = 3; // [2:0.5:8]

/* [Grid] */
// Concentric rings, counting the rim around the hole and the outer rim.
rings = 4; // [2:1:10]
// even: rings at equal distance. square: geometric, so every cell keeps the same shape.
ring_spacing = "square"; // [even, square]
// Spokes per segment: one edge spoke plus the spokes inside the segment.
spokes_per_segment = 4; // [1:1:10]
// Add a spoke between every pair from this ring outward (0 = outer rim). 0 turns it off.
outer_spokes_from = 2; // [0:1:9]
// Degrees a spoke turns between hole and rim. Zero gives straight spokes.
swirl = 30; // [-120:5:120]

/* [Split] */
// Number of segments the guard is cut into.
segments = 4; // [2, 3, 4]
// Width of the cut between the two edge spokes of neighbouring segments.
gap = 1; // [0.5:0.1:3]
// parallel: edge spokes shifted beside the cut, constant gap. radial: pointing at the centre.
edge_mode = "parallel"; // [parallel, radial]
// The whole guard, or one segment flipped into print orientation.
part = "all"; // [all, one]

/* [Spikes] */
// Length of the spikes below the plate. Zero removes them.
spike_len = 25; // [0:1:60]
// Diameter of a spike at its base.
spike_w = 4; // [2:0.5:10]
// A spike on every n-th ring, counted from the outer rim inward.
spike_ring_step = 2; // [1:1:5]
// A spike on every n-th spoke, counted from the edge spoke of each segment.
spike_spoke_step = 2; // [1:1:6]

/* [Polish] */
// Radius the bar corners are rounded to. Zero keeps them sharp.
round_r = 0.5; // [0:0.25:2]

/* [Quality] */
// Facets on the rings. More is smoother and slower.
smoothness = 96; // [32:16:192]

/* [Colour] */
// Display only, the STL carries no colour.
color_grid = "ForestGreen"; // [ForestGreen, Silver, Gainsboro, White, DimGray, Black, SlateGray, FireBrick, SteelBlue, Goldenrod]

/* [Hidden] */
hole = min(hole_d, diameter - 4 * bar_w - 10);
r_out = diameter / 2 - bar_w / 2;   // centre line of the outer rim
r_in = hole / 2 + bar_w / 2;         // centre line of the rim around the hole
spokes = segments * spokes_per_segment;
seg_a = 360 / segments;
edge_off = (gap + bar_w) / 2;                       // sideways shift of a parallel edge spoke
delta = asin(min(0.9, (gap + bar_w) / (2 * r_in))); // rotation of a radial edge spoke
split_ring = min(outer_spokes_from, rings - 1);
steps = swirl == 0 ? 1 : 24;
r_polish = min(round_r, bar_w / 2 - 0.3, gap / 2 - 0.1);

// Ring i, with 0 the outer rim and rings-1 the rim around the hole.
function ring_r(i) = ring_spacing == "square"
  ? r_out * pow(r_in / r_out, i / (rings - 1))
  : r_out - i * (r_out - r_in) / (rings - 1);
// Spoke j: its base angle, and whether it lies on a cut.
function spoke_a(j) = j * 360 / spokes;
function on_cut(j) = j % spokes_per_segment == 0;
// Sides a spoke is drawn on: two bars beside a cut, one bar elsewhere.
function spoke_sides(j) = on_cut(j) ? [-1, 1] : [0];

// ---- Paths ----
// A spoke of base angle a follows theta(a, r): straight, or turning by swirl from hole to rim.
function tt(r) = max(0, min(1, (r - r_in) / (r_out - r_in)));
function theta(a, r) = a + swirl * tt(r);
function dtheta(r) = (r > r_in && r < r_out) ? swirl * PI / 180 / (r_out - r_in) : 0;
function tangent_a(a, r) = theta(a, r) + atan(r * dtheta(r));
function polar(r, a) = r * [cos(a), sin(a)];
function nrm(a, r) = let(f = tangent_a(a, r)) [-sin(f), cos(f)];
// Point on spoke a, side s (-1, 0, 1), at radius r.
function pt(a, s, r) = edge_mode == "radial"
  ? polar(r, theta(a + s * delta, r))
  : polar(r, theta(a, r)) + s * edge_off * nrm(a, r);
function path(a, s, r0, r1, n) = [for (k = [0 : n]) pt(a, s, r0 + (r1 - r0) * k / n)];
function reverse(v) = [for (i = [len(v) - 1 : -1 : 0]) v[i]];

// A stroke of width w along a list of points.
module stroke(pts, w) {
  for (k = [0 : len(pts) - 2])
    hull() {
      translate(pts[k]) circle(d = w, $fn = 16);
      translate(pts[k + 1]) circle(d = w, $fn = 16);
    }
}

// The polish: a closing pass rounds the concave corners, an opening pass the convex ones.
module polish2d(r) {
  if (r > 0)
    offset(r = r, $fn = 24) offset(r = -2 * r, $fn = 24) offset(r = r, $fn = 24) children();
  else
    children();
}

// ---- Grid pattern ----
// Rings, the spokes inside the segments and the extra outer spokes. The edge spokes are
// added after the cuts, see body2d.
module grid_core2d() {
  for (i = [0 : rings - 1])
    difference() {
      circle(r = ring_r(i) + bar_w / 2, $fn = smoothness);
      circle(r = ring_r(i) - bar_w / 2, $fn = smoothness);
    }
  for (j = [0 : spokes - 1])
    if (!on_cut(j))
      stroke(path(spoke_a(j), 0, r_in, r_out, steps), bar_w);
  if (outer_spokes_from > 0)
    for (j = [0 : spokes - 1])
      stroke(path(spoke_a(j) + 180 / spokes, 0, ring_r(split_ring), r_out, steps), bar_w);
}

module edge_spokes2d() {
  for (j = [0 : spokes - 1], s = spoke_sides(j))
    if (s != 0)
      stroke(path(spoke_a(j), s, r_in, r_out, steps), bar_w);
}

// Width of the cut at radius r: the gap, or the wedge between two radial edge spokes.
function cut_w(r) = (edge_mode == "radial" ? max(gap, 2 * r * sin(delta) - bar_w * cos(delta)) : gap) + 0.4;

module cuts2d() {
  R = diameter / 2 + 5;
  n = 24;
  for (k = [0 : segments - 1]) {
    a = spoke_a(k * spokes_per_segment);
    for (m = [0 : n - 1])
      hull() {
        translate(pt(a, 0, R * m / n)) circle(d = cut_w(R * m / n), $fn = 16);
        translate(pt(a, 0, R * (m + 1) / n)) circle(d = cut_w(R * (m + 1) / n), $fn = 16);
      }
  }
}

// ---- Plate ----
module body2d() {
  polish2d(r_polish)
    union() {
      difference() { grid_core2d(); cuts2d(); }
      edge_spokes2d();
    }
}

// One segment: the wedge between cut 0 and cut 1, following the cut paths.
module wedge2d() {
  R = diameter / 2 + 8;
  a0 = spoke_a(0);
  a1 = spoke_a(spokes_per_segment);
  polygon(concat(
    [[0, 0]],
    path(a0, 0, 0.5, R, 24),
    [for (a = [theta(a0, R) : 2 : theta(a1, R)]) polar(R, a)],
    reverse(path(a1, 0, 0.5, R, 24))));
}

module plate() {
  linear_extrude(height = thickness)
    if (part == "one") intersection() { body2d(); wedge2d(); }
    else body2d();
}

// ---- Spikes ----
// Plain cones hanging below the plate at ring/spoke crossings, clipped to the outer
// diameter so nothing sticks out past the rim.
module spike() {
  translate([0, 0, 0.5]) mirror([0, 0, 1])
    cylinder(h = spike_len + 0.5, d1 = spike_w, d2 = 0.6, $fn = 24);
}

module spikes() {
  if (spike_len > 0)
    intersection() {
      for (i = [0 : rings - 1], j = [0 : spokes - 1], s = spoke_sides(j))
        if (i % spike_ring_step == 0 && j % spike_spoke_step == 0)
          translate(pt(spoke_a(j), s, ring_r(i))) spike();
      translate([0, 0, -spike_len - 1])
        linear_extrude(height = spike_len + 2)
          if (part == "one") intersection() { circle(d = diameter, $fn = smoothness); wedge2d(); }
          else circle(d = diameter, $fn = smoothness);
    }
}

// ---- Layout ----
if (part == "one") {
  // Flipped onto its plate side, spikes up: the print orientation.
  color(color_grid) rotate(-seg_a / 2) translate([0, 0, thickness]) mirror([0, 0, 1]) {
    plate();
    spikes();
  }
} else {
  color(color_grid) { plate(); spikes(); }
}

Comments

Context, not a score. Comments never move a model up or down the results.

No comments yet

Printed it? A note about your material and the clearance you landed on saves the next person a failed print.

Sign in to comment