Works out the cut length of every wire from its route through a harness drawing or between two modules in a cabinet, and the diameter of each bundle.
How the precision is kept
Segment lengths are 64-bit distances between drawn nodes, or the length a person typed for the segment. The shortest route adds segment lengths in path order. The result is an estimate by design: an allowance is added at each end, a cabinet run is the rectangular distance times a slack factor, and a bundle diameter uses a packing factor.
Calculations under this policy
4 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
The length in millimeters of each drawn harness segment.
len = √(Δx² + Δy²) ÷ k (k = drawing units per mm), unless a length is typed
Math.hypot on the node coordinates, then one division by the drawing scale. A typed length that is finite and above zero replaces the measured one.
addons/harness/lib/route.js
lines 19 to 32
CadCraft 0.8.2
/** h = { k (drawing units per mm), nodes: [{ id, x, y }], segs: [{ id, a, b, len? }] }. */
export function harnessGraph(h) {
const k = h.k || 1;
const nodes = new Map(h.nodes.map((n) => [n.id, { x: n.x, y: n.y }]));
const segs = new Map(), adj = new Map();
for (const s of h.segs) {
const a = nodes.get(s.a), b = nodes.get(s.b);
if (!a || !b) continue;
const len = Number.isFinite(s.len) && s.len > 0 ? s.len : Math.hypot(a.x - b.x, a.y - b.y) / k;
segs.set(s.id, { id: s.id, a: s.a, b: s.b, len });
for (const [x, y] of [[s.a, s.b], [s.b, s.a]]) (adj.get(x) || adj.set(x, []).get(x)).push({ to: y, seg: s.id, len });
}
return { nodes, segs, adj };
}
Shortest route between two nodes
64-bit
The segments a wire runs through and their total length.
len = Σ segment lengths along the shortest path
Lengths are added one segment at a time in path order; all terms are positive, so nothing cancels. Two routes of equal length are decided by which was found first.
addons/harness/lib/route.js
lines 34 to 52
CadCraft 0.8.2
export function shortestPath(g, from, to) {
if (!g.nodes.has(from) || !g.nodes.has(to)) return null;
if (from === to) return { segs: [], nodes: [from], len: 0 };
const dist = new Map([[from, 0]]), prev = new Map(), done = new Set();
for (;;) {
let u = null, best = Infinity;
for (const [n, d] of dist) if (!done.has(n) && d < best) { best = d; u = n; }
if (u === null) return null;
if (u === to) break;
done.add(u);
for (const e of g.adj.get(u) || []) {
const nd = best + e.len;
if (nd < (dist.get(e.to) ?? Infinity)) { dist.set(e.to, nd); prev.set(e.to, { from: u, seg: e.seg }); }
}
}
const segs = [], nodes = [to];
for (let n = to; n !== from;) { const p = prev.get(n); segs.unshift(p.seg); nodes.unshift(p.from); n = p.from; }
return { segs, nodes, len: dist.get(to) };
}
Bundle diameter
64-bit
The diameter of a bundle of wires from their outside diameters.
D = √(Σ dᵢ² ÷ packing)
A sum of squares and one square root. The packing factor, 0.7 unless given, is an assumption about how tightly round wires pack, and it sets the accuracy.
addons/harness/lib/route.js
lines 54 to 57
CadCraft 0.8.2
export function bundleDiameter(ods, packing = 0.7) {
const area = ods.reduce((s, d) => s + d * d, 0);
return area ? Math.sqrt(area / packing) : 0;
}
Cut length of each wire
64-bit
Each wire's length with its end allowances, and which wires share each harness segment.
Plain 64-bit sums. The cabinet length is the rectangular distance between module centers times the slack factor, not a route through the drawn ducts. A typed length is returned unchanged as both the base and the cut length.
addons/harness/lib/route.js
lines 59 to 95
CadCraft 0.8.2
/**
* connections: [{ key, a: { device: { tag, uid } }, b }], getSpec(conn) → merged spec,
* harnesses: [{ id, graph }], ends: Map device tag → { harness id, node id }, modules: Map device tag → { x, y } (mm, centres in the cabinet).
* → route { how: 'harness' | 'cabinet' | 'length' | null, mm (with allowances; null = unknown), segs, harness, base (without allowances) }
*/
export function routeAll(connections, getSpec, { harnesses = [], ends = new Map(), modules = new Map(), allow = 15, loop = 0, slack = 1.1 } = {}) {
const routes = new Map(), segments = new Map();
const gOf = new Map(harnesses.map((h) => [h.id, h.graph]));
for (const c of connections) {
const spec = getSpec(c), da = c.a.device, db = c.b.device, ta = partId(da), tb = partId(db);
let route = { how: null, mm: null, base: null, segs: [], harness: null };
const extra = 2 * allow + loop;
if (spec.l) route = { how: 'length', base: spec.l, mm: spec.l, segs: [], harness: null };
else {
const ea = ends.get(ta) || ends.get(da.tag), eb = ends.get(tb) || ends.get(db.tag);
if (ea && eb && ea.harness === eb.harness && gOf.has(ea.harness)) {
const p = shortestPath(gOf.get(ea.harness), ea.node, eb.node);
if (p) route = { how: 'harness', base: p.len, mm: p.len + extra, segs: p.segs, harness: ea.harness };
} else if (modules.has(ta) && modules.has(tb)) {
const a = modules.get(ta), b = modules.get(tb);
const base = (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) * slack;
route = { how: 'cabinet', base, mm: base + extra, segs: [], harness: null };
}
}
routes.set(c.key, route);
if (route.how === 'harness') {
for (const s of route.segs) {
const key = route.harness + '/' + s;
const g = segments.get(key) || segments.set(key, { harness: route.harness, seg: s, wires: [], ods: [] }).get(key);
g.wires.push(spec.i || c.a.name + '>' + c.b.name);
const od = diameterOf(spec.g);
if (od) g.ods.push(od);
}
}
}
return { routes, segments };
}
In detail
Method
Shortest path by Dijkstra's method over the harness graph. Cabinet: (|Δx| + |Δy|) × slack. Bundle: √(Σd² ÷ packing).
Number types
64-bit numbers.
Tolerances
Defaults: 15 mm allowance at each end, no service loop, cabinet slack 1.1, packing 0.7.
Limits
A length typed on the wire is used as it is, with no allowance added.
Approach: 64-bit, stated limit
The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.