Resources Numerical accuracy Calculation policy

Wire lengths through a harness or a cabinet

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.

addons/harness/lib/route.js CadCraft 0.8.2 64-bit 4 calculations Reviewed

Tests None found by the review

Harness segment lengths

64-bit

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.

harness: route + 2 × allow + loop; cabinet: (|Δx| + |Δy|) × slack + 2 × allow + loop

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.

Every policy that takes this approach