The idea of creating a robust arc module for OpenSCAD is simple: we want to generate a circular sector or annular arc between two radii \(r_1\) and \(r_2\), bounded by two angles \(\alpha_1\) and \(\alpha_2\). A common approach subtracts circles and trims with a large triangle, but that relies on arbitrary constants and can fail outside the first quadrant. Instead, we can construct the annular sector polygon directly, which works for all quadrants and angle sweeps.
// https://raw.org/snippet/circular-sector-and-arcs-with-openscad/
//
// Annular sector module for OpenSCAD
// r1, r2: radii in any order (inner/outer auto-detected)
// a1, a2: start/end angles (degrees; any order; wrap handled)
// res: number of segments per 360° (quality); or set $fn globally
module arc(r1, r2, a1, a2, $fn=128) {
r0 = min(r1, r2);
r1 = max(r1, r2);
function N(a) = (a % 360 + 360) % 360;
a = N(a1);
b = N(a2);
s = let(d = (b - a) % 360) (d < 0 ? d + 360 : d); // sweep in [0,360)
if (s == 0) {
difference() {
circle(r = r1, $fn = $fn);
if (r0 > 0) circle(r = r0, $fn = $fn);
}
} else {
k = max(3, ceil($fn * s / 360));
function pts(R, A, S, K) = [ for (i = [0:K]) [ R * cos(A + S * i / K), R * sin(A + S * i / K) ] ];
polygon(concat(pts(r1, a, s, k), pts(r0, b, -s, k)));
}
}
Extruding into 3D
Since the module creates a clean 2D geometry, it can be extruded directly:
module arc3d(r1, r2, a1, a2, h, res=128) {
linear_extrude(height = h)
arc(r1, r2, a1, a2, res);
}
Examples
arc(10, 20, 0, 45); // small arc, radii swapped automatically
arc(150, 120, 0, 90); // large annular sector, no magic constants
arc(150, 120, 0, 170); // works outside the first quadrant
arc(150, 120, 350, 10); // sweep across 0°, handled correctly
arc(50, 0, 0, 0); // full circle with radius 50
Notes
- Angles are in degrees, consistent with OpenSCAD’s sin() and cos().
- Radii can be given in any order; the module ensures r_outer ≥ r_inner.
- If a1 == a2, the result is a full ring (or full disk if the inner radius is 0).
- Smoothness can be controlled per call via res or globally with $fn, $fs, $fa.