From e47562649761d56d9c3ed8256e484fabd07f8cc1 Mon Sep 17 00:00:00 2001 From: sjat Date: Mon, 8 Jun 2026 22:13:58 +0200 Subject: [PATCH] fix: guard flattenArc against zero-radius (degenerate) arcs Co-Authored-By: Claude Opus 4.8 (1M context) --- src/geometry/arc.test.ts | 5 +++++ src/geometry/arc.ts | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/geometry/arc.test.ts b/src/geometry/arc.test.ts index d5adebe..260151e 100644 --- a/src/geometry/arc.test.ts +++ b/src/geometry/arc.test.ts @@ -32,4 +32,9 @@ describe('flattenArc', () => { const fine = flattenArc([10, 0], [0, 10], [0, 0], false, 0.01); expect(fine.length).toBeGreaterThan(coarse.length); }); + + it('returns a straight segment for a degenerate zero-radius arc', () => { + const pts = flattenArc([5, 5], [5, 5], [5, 5], false, 0.1); + expect(pts).toEqual([[5, 5], [5, 5]]); + }); }); diff --git a/src/geometry/arc.ts b/src/geometry/arc.ts index 326eb15..4b55238 100644 --- a/src/geometry/arc.ts +++ b/src/geometry/arc.ts @@ -16,6 +16,10 @@ export function flattenArc( clockwise: boolean, tolerance = 0.2, ): Vec2[] { + // Degenerate (zero-radius) arc: nothing to sweep, return a straight segment. + const r0 = Math.hypot(start[0] - center[0], start[1] - center[1]); + if (r0 < 1e-9) return [[start[0], start[1]], [end[0], end[1]]]; + const radius = Math.hypot(start[0] - center[0], start[1] - center[1]); const startAngle = Math.atan2(start[1] - center[1], start[0] - center[0]); const endAngle = Math.atan2(end[1] - center[1], end[0] - center[0]); @@ -27,7 +31,7 @@ export function flattenArc( while (sweep <= 0) sweep += 2 * Math.PI; // sweep in (0, 2π] } - const maxStep = radius > tolerance ? 2 * Math.acos(1 - tolerance / radius) : Math.PI / 8; + const maxStep = radius > tolerance ? 2 * Math.acos(1 - tolerance / radius) : Math.PI / 8; // fallback step for tiny radii const steps = Math.max(1, Math.ceil(Math.abs(sweep) / maxStep)); const pts: Vec2[] = [];