openscad

In OpenSCAD, is it possible to parameterize the shape being extruded?


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);
    }
}

Solution

  • 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);
    

    demonstration of extrude_between

    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.

    stacked extrusions used to vary parameters in a nonlinear way