raw snippet

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