I’m using OpenSCAD for all designs that I want to 3D print. Recently I wanted to have curved surfaces for a door handle repair, and OpenSCAD natively only supports straight lines and circles.

Using list comprehension, a parametric equation can be calculated at a number of points to approximate many curves

I thus wrote functions for computing the points of cubic and quadratic Bezier curves, as formulas are rather simple:

P1 * (1 -t)^2 + 2 * P2 * (1 -t) * t + P3 * t^2
P1 * (1 -t)^3 + 3 * P2 * (1 -t)^2 * t + 3 * P3 * (1 -t) * t^2 + P4 * t^3

Functions takes control points as an array of positions [x, y] and the number of steps to generate. Steps are generated with a range, and to make sure upper bound is included I did not use [0 : 1/steps : 1] but rather [0 : steps] with t/steps.

function bezier_quadratic_point(c1, c2, c3, c4, t) =
  c1 * pow(1 - t, 3)
  + 3 * c2 * t * pow(1 - t, 2)
  + 3 * c3 * pow(t, 2) * (1 - t)
  + c4 * pow(t, 3);

function bezier_quadratic(p1, p2, p3, p4, steps = 50) =
  [for(t = [0 : steps]) [bezier_quadratic_point(p1[0], p2[0], p3[0], p4[0], t / steps), bezier_quadratic_point(p1[1], p2[1], p3[1], p4[1], t / steps)]];

function bezier_cubic_point(c1, c2, c3, t) =
  c1 * pow(1 - t, 2)
  + 2 * c2 * t * (1 - t)
  + c3 * pow(t, 2);

function bezier_cubic(p1, p2, p3, steps = 50) =
  [for(t = [0 : steps]) [bezier_cubic_point(p1[0], p2[0], p3[0], t), bezier_cubic_point(p1[1], p2[1], p3[1], t / steps)]];

This could be generalized to a function that takes an arbitrary number of points and compute the sum of products for binomial coefficients. It can be generalized to points of arbitraty size to support 3D lines. But I’m not mastering OpenSCAD language, cubic/quadratic were sufficient for my project, and I’m extruding 2D surfaces. Yet this might be a subject for playing with the language in the future.

In order to include these lines a complex object, I concatenate arrays of points in a polygon and extrude the resulting shape.

rotate_extrude($fn = 100) {
  polygon(concat(
    [[0, 0], [20, 0]],
    bezier_cubic([20, 0], [30, 0], [30, 25]),
    bezier_quadratic([30, 25], [30, 50], [10, 25], [10, 50]),
    [[0, 50]]
  ));
}