I created a module in OpenSCAD to create a container with periodic bumps. It works, but I wanted to change the amplitude of the bumps with elevation.
ChatGPT claimed that there is a parameter $t that varies along the extrusion, but I could not find it in the docs, nor any examples. I think it's hallucinating. In fact, I can only see the echo evaluating once.
Is there any way to pass to each layer of linear_extrude what level it is on? I don't need an absolute z number, the parameter will do. But as far as I can determine, $t isn't doing anything.
function f(r, t, T, peak_width, a) =
(t % T > peak_width) ?
r : r + a * sin(180 * (t % T) / peak_width);
module periodic_envelope(da, r, num_bumps, peak_width, amplitude) {
T = 360/num_bumps;
pts = [ for (t = [0:da:360])
[f(r, t, T, peak_width, amplitude) * cos(t),
f(r, t, T, peak_width, amplitude) * sin(t)]
];
polygon(pts);
}
peak_width = 18.0; //degrees
amplitude = 10;
r = 30;
thickness = 2;
da = 0.5;
num_bumps = 4;
linear_extrude(height = 120, scale=1.2) {
echo ("test, $t); // seems not work?
a = amplitude *(1 +$t);
difference() {
periodic_envelope(da, r, num_bumps, peak_width, a);
periodic_envelope(da, r-thickness, num_bumps, peak_width, a);
}
}
With OpenSCAD, you sometimes have to roll your own operations.
I hacked together this extrude_between
module that takes two 2D polygons, offsets them in the z-axis, and connects the corresponding points into a closed polyhedron. It could be modified to do even more.
// HACK: The points must be specified counterclockwise in order for the
// polyhedron faces to be clockwise.
module extrude_between(points0, points1, height, convexity=2) {
N = len(points0);
assert(len(points1) == N);
bottom_pts = [for (i=[0:N-1]) [points0[i].x, points0[i].y, 0]];
top_pts = [for (i=[0:N-1]) [points1[i].x, points1[i].y, height]];
bottom_face = [for (i=[0:N-1]) i];
top_face = [for (i=[0:N-1]) 2*N - i - 1];
side_faces = [for (i=[0:N-1]) let (j=(i+1)%N) [i+N, j+N, j, i]];
polyhedron(
[each bottom_pts, each top_pts],
[bottom_face, each side_faces, top_face],
convexity=convexity
);
}
Then I transformed your periodic_envelope
module to make it a function that just returns the points.
function periodic_envelope(da, r, num_bumps, peak_width, amplitude) =
let (T = 360/num_bumps)
[ for (t = [0:da:360])
[f(r, t, T, peak_width, amplitude) * cos(t),
f(r, t, T, peak_width, amplitude) * sin(t)]];
It works for a simple linear interpolation of one of your parameters like the amplitude.
points0 = periodic_envelope(da, r, num_bumps, peak_width, 3*amplitude);
points1 = periodic_envelope(da, r, num_bumps, peak_width, amplitude);
extrude_between(points0, points1, 120, convexity=4);
Hollowing it out is left as an exercise. :-)
If you wanted to vary the amplitude in a more interesting way, you could stack layers.
for (slice = [1:120]) {
amplitude0 = amplitude*sin(slice*5);
amplitude1 = amplitude*sin((slice+1)*5);
points0 = periodic_envelope(da, r, num_bumps, peak_width, amplitude0);
points1 = periodic_envelope(da, r, num_bumps, peak_width, amplitude1);
translate([0, 0, slice]) {
extrude_between(points0, points1, 1);
}
}
Caution: This is not optimized, so rendering can get pretty slow as you increase the level of detail.