Cables and their routes
64-bitOne cable per circuit with its route length, plus the fill of every tray and conduit it runs in.
point in mm = plan point × (meters per unit × 1000); cable route = the longest of the board-to-device routes
Coordinates are multiplied by one 64-bit factor; a missing meters-per-unit value is taken as 0.001. Of the routes found from the board to each device, the one with the greatest length is kept by a plain comparison. Lengths, slack and fill come from the engine files.
export function planCarriers({ routes, inst, mpu, cableOd = {}, reachMm = 500, limits = FILL_DEFAULTS.conduit, trayPct = FILL_DEFAULTS.tray, slack = 0.1, endsMm = 1000 }) {
const mm = (mpu || 0.001) * 1000;
const cables = [], routeOut = new Map(), runInfo = {}, unrouted = [], noOd = new Set();
const bySpace = new Map(), labelOf = new Map();
for (const rr of routes) { const spec = parseCarrierLayer(rr.layer); if (spec) runInfo['R' + rr.id] = { ...spec, label: String(rr.layer).replace(/^EL-ROUTE-/i, '') }; }
for (const r of routes) { const k = r.space?.key ?? ''; if (!bySpace.has(k)) bySpace.set(k, []); bySpace.get(k).push(r); }
for (const c of inst.circuits.values()) {
if (!c.board || !c.loads.length) continue;
const spaceKey = c.board.space?.key ?? '';
const rs = bySpace.get(spaceKey) || [];
const runs = rs.map((r) => ({ id: 'R' + r.id, verts: r.pts.map((p) => [p.x * mm, p.y * mm, 0]) }));
const bKey = 'board:' + c.board.uid;
const loads = c.loads.filter((l) => (l.space?.key ?? '') === spaceKey);
const points = [{ key: bKey, p: [c.board.at.x * mm, c.board.at.y * mm, 0] }, ...loads.map((l) => ({ key: 'load:' + l.uid, p: [l.at.x * mm, l.at.y * mm, 0] }))];
const graph = graphFromRuns(runs, points, { tol: reachMm });
for (const l of loads) labelOf.set('load:' + l.uid, [l.label, l.attrs?.TAG].filter(Boolean).join(' ') || String(l.id));
const legs = loads.map((l) => ({ tag: c.name + '|' + l.uid, from: bKey, to: 'load:' + l.uid }));
const r = routeCables(graph, legs);
let best = null;
for (const leg of legs) { const x = r.get(leg.tag); if (x?.found && (!best || x.lengthMm > best.x.lengthMm)) best = { leg, x }; }
if (!best) { unrouted.push(c.name); cables.push({ tag: c.name, circuit: c.name, type: c.cable, odMm: odOf(c.cable, cableOd), n: 1, from: c.board.tag || 'board', to: '', _none: true }); continue; }
const cable = { tag: c.name, circuit: c.name, type: c.cable, size: '', odMm: odOf(c.cable, cableOd), n: 1, from: c.board.tag || 'board', to: labelOf.get(best.leg.to) || '' };
if (!cable.odMm) noOd.add(c.cable || c.name);
cables.push(cable);
routeOut.set(c.name, best.x);
}
const routed = cables.filter((c) => !c._none);
const rows = scheduleRows(cables, new Map([...routeOut, ...cables.filter((c) => c._none).map((c) => [c.tag, { found: false, runs: [], lengthMm: 0, why: 'ends' }])]), { slack, endsMm });
const fills = fillByRun(routed, routeOut, runInfo, { limits, trayPct }).map((f) => ({ ...f, noDiameter: f.cables.some((tag) => !routed.find((c) => c.tag === tag)?.odMm) }));
return { cables, routes: routeOut, rows, fills, unrouted, noOd: [...noOd] };
}