Cut parameters
64-bitWhere along an object each cutting edge crosses it.
t = segment index + parameter of the intersection; t = round(t × 10⁹) ÷ 10⁹
Each intersection point is converted to a parameter with primParam, and for every object except a construction line the parameter is rounded to 9 decimals with Math.round before it is used. The cut point is later recomputed from this rounded value, which moves it by up to 5 × 10⁻¹⁰ of the segment's length. For construction lines the parameter is kept as computed and values closer than 1e-15 are merged.
/** Parameter along the whole entity: poly → segment index + local t; circle/arc → fraction of sweep. */
function entityParams(e, cutters, blocks, edgeExtend = false) {
const own = e.type === 'poly' ? polyPrims(e) : prims(e);
const ts = [];
own.forEach((p, i) => {
// EDGEMODE 1: a cutting line or arc counts as the whole line or circle it lies on
for (const c of cutters) for (const q of prims(c, blocks)) for (const x of intersect(p, q, false, edgeExtend && (c.type === 'line' || c.type === 'arc'))) {
let t = primParam(p, x);
if (p.rev) t = 1 - t;
ts.push((e.type === 'poly' ? i : 0) + t);
}
});
if (UNBOUNDED.has(e.type)) { // a stand-in segment 2·FAR long: rounding t would move a cut by metres; keep it exact
const u = ts.sort((a, b) => a - b).filter((t, i, l) => !i || t - l[i - 1] > 1e-15);
return { own, ts: u };
}
return { own, ts: [...new Set(ts.map((t) => Math.round(t * 1e9) / 1e9))].sort((a, b) => a - b) };
}