Offset of one edge
64-bitOne edge of the sew line moved outward by its allowance.
n = (tᵧ, −tₓ); moved point = p + n·w; join = meeting point of the two moved lines when |t₁ × t₂| > 1e-9 and it is within 4·w of the vertex
The unit direction is formed with Math.hypot and segments shorter than 1e-12 are left out. Where a join is not used, both moved end points are kept, which cuts the corner straight across.
/** A polyline moved w to its right; neighbouring segments joined where their moved lines meet. */
export function offsetOpen(path, w) {
const p = clean(path);
if (p.length < 2 || !(w > 0)) return p.map((q) => ({ ...q }));
const segs = [];
for (let i = 0; i + 1 < p.length; i++) { const t = unit(p[i], p[i + 1]); if (t) segs.push({ a: p[i], b: p[i + 1], t, n: right(t) }); }
if (!segs.length) return [p[0]];
const out = [add(segs[0].a, segs[0].n, w)];
for (let i = 0; i + 1 < segs.length; i++) {
const s = segs[i], u = segs[i + 1];
const a = add(s.b, s.n, w), b = add(u.a, u.n, w);
const hit = Math.abs(cross(s.t, u.t)) > 1e-9 ? meet(a, s.t, b, u.t) : null;
if (hit && Math.hypot(hit.x - s.b.x, hit.y - s.b.y) < w * 4) out.push({ x: hit.x, y: hit.y });
else { out.push(a); out.push(b); }
}
const last = segs[segs.length - 1];
out.push(add(last.b, last.n, w));
return out;
}