Resources Numerical accuracy Calculation policy

KISS file: quantities, sizes and weights

Writes the bill of materials as a KISS file for fabrication software: quantities, sizes, lengths, weights and plate areas.

How the precision is kept

Lengths and labor sizes are written in millimeters with two decimals, which the file's header says the standard asks for. Imperial files convert weight and area with decimal constants rounded to 12 significant digits, and plate and bolt sizes to the nearest 1/16 inch. Quantities are whole-number counts.

Open item. Divide by 0.45359237 and by 0.09290304 instead of multiplying by the rounded constants, so the factors are the exact definitions.

Calculations under this policy

6 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.

kiss.js DetailCraft 0.8.1 64-bit 6 calculations Reviewed

Tests bin/test-detailcraft.mjs

Conversion constants and two-decimal rounding

64-bit

The pound and inch factors and the helper that writes two decimals.

lb = kg × 2.20462262185; in = mm ÷ 25.4; f2(v) = round(v × 100) ÷ 100

25.4 is exact. 2.20462262185 is the pound factor rounded to 12 significant digits; the exact value is 1 ÷ 0.45359237. f2 rounds with Math.round and then prints two decimals.

  • kiss.js
  • lines 33 to 36
  • DetailCraft 0.8.1
const KG_LB = 2.20462262185;
const IN = 25.4;
const clean = (s, n) => String(s ?? '').replace(/[,\r\n\u0000-\u001f\u007f]/g, ' ').replace(/\s+/g, ' ').trim().slice(0, n);
const f2 = (v) => (Math.round(v * 100) / 100).toFixed(2);

Weight and plate area fields

64-bit

The weight and area written on a line, in metric or imperial units.

weight = kg, or kg × 2.20462262185 lb; area = m², or m² × 10.7639104167 sq ft

10.7639104167 is 1 ÷ 0.09290304 rounded to 12 significant digits. The relative error of each constant is below 1 × 10⁻¹², and both results are then rounded to two decimals.

  • kiss.js
  • lines 84 to 85
  • DetailCraft 0.8.1
const W = (kg) => f2(metric ? kg : kg * KG_LB);
const area = (m2) => f2(metric ? m2 : m2 * 10.7639104167);

Inches as a fraction to 1/16

64-bit

Writes a plate or bolt size in inches and sixteenths.

n = round(inches × 16); whole = ⌊n ÷ 16⌋; fraction reduced by halving

Rounds to the nearest 1/16 with Math.round, then reduces the fraction with whole-number steps. A size that is not a multiple of 1/16 inch is changed by up to 1/32 inch in the size text.

  • kiss.js
  • lines 39 to 47
  • DetailCraft 0.8.1
/** Inches to a fraction string to 1/16: 12.375 → "12-3/8", 0.5 → "1/2", 3 → "3". */
export function inchFraction(inches, denom = 16) {
  let n = Math.round(inches * denom);
  const whole = Math.floor(n / denom);
  let num = n - whole * denom, den = denom;
  while (num && num % 2 === 0) { num /= 2; den /= 2; }
  if (!num) return String(whole);
  return (whole ? whole + '-' : '') + num + '/' + den;
}

Size designation

64-bit

The type code and size text of a part's profile.

Metric plates are written as thickness × width, each rounded to two decimals. Imperial plates divide by 25.4 and go through inchFraction. Rolled shapes keep their designation; an HSS wall given as a fraction is written as a 3-decimal number.

  • kiss.js
  • lines 54 to 70
  • DetailCraft 0.8.1
/** [type code, size string] for a part's profile. */
export function kissShape(profile, metric) {
  const p = profile, name = String(p.name).toUpperCase();
  if (p.kind === 'PL') {
    const t = p.t, w = p.b;
    return ['PL', metric ? f2c(t) + 'X' + f2c(w) : inchFraction(t / IN) + 'X' + inchFraction(w / IN)];
  }
  if (p.source === 'aisc') {
    const m = name.match(/^(W|S|C|L|HSS)(.*)$/);
    if (m) {
      if (m[1] === 'HSS') { const parts = m[2].split('X'); parts[parts.length - 1] = decWall(parts[parts.length - 1]); return ['HSS', parts.join('X')]; }
      return [m[1], m[2]];
    }
  }
  if (p.source === 'en') return [p.kind === 'C' ? 'C' : 'W', name];   // UPN is a channel
  return [{ I: 'MI', C: 'MI', L: 'MI', RHS: 'MI', CHS: 'MI' }[p.kind] || 'MI', name];
}

Detail line: quantity, length, weight, area

64-bit

One D line of the file for a part mark.

plate area m² = width × length ÷ 10⁶

The quantity is rounded to a whole number and the length is written in mm with two decimals. Plate area is width × length from 64-bit millimeters. The header notes that net weight is left empty because holes are not taken off.

  • kiss.js
  • lines 101 to 105
  • DetailCraft 0.8.1
const dline = (dwg, rev, asm, mark, qty, part) => {
  const [type, size] = kissShape(part.profile, metric);
  put('D', clean(dwg, 30), clean(rev, 5), clean(asm, 16), clean(mark, 16), Math.round(qty), type, clean(size, 24), grade(part.material), f2(part.length), '', clean(part.role || ROLE[part.type], 40),
    clean(part.name || part.role || ROLE[part.type], 30), '', W(part.weight), '', part.profile.kind === 'PL' ? area(part.profile.b * part.length / 1e6) : '');
};

Hole counts by size

64-bit

The labor lines that count a part's holes by diameter and thickness.

Holes are grouped by diameter and thickness after both are rounded to two decimals, so holes whose sizes round to the same two decimals are counted together. For a hole in the web of a rectangular hollow section the thickness written is twice the wall.

  • kiss.js
  • lines 90 to 99
  • DetailCraft 0.8.1
const labor = (part) => {
  const holes = new Map();
  for (const h of part.holes) {
    const t = part.profile.kind === 'PL' ? part.profile.t : h.face === 'web' ? (part.profile.kind === 'RHS' ? part.profile.t * 2 : part.profile.tw) : (part.profile.kind === 'RHS' ? part.profile.t : part.profile.tf);
    const k = f2(h.d) + '|' + f2(t);
    holes.set(k, (holes.get(k) || 0) + 1);
  }
  for (const [k, n] of holes) { const [dd, t] = k.split('|'); put('L', 'Holes', n, dd, t, 'Round'); }
  for (const c of part.cuts.filter((x) => x.kind === 'cope')) put('L', 'Copes', 1, f2(c.depth), f2(c.length), clean('Cope ' + c.side + ' at ' + c.end, 40));
};

In detail

Method
The KISS standard version 1.1 as described in the file's header: comma-delimited lines, D lines per part mark with quantity, size, length, weight and area, and L lines for holes, copes and welds.
Number types
64-bit numbers; text with two decimals; whole-number quantities.
Limits
kg to lb uses 2.20462262185 where 1 ÷ 0.45359237 = 2.2046226218487757…, and m² to sq ft uses 10.7639104167 where 1 ÷ 0.09290304 = 10.763910416709722…. Each differs from the exact factor by less than 1 part in 10¹². Imperial sizes are rounded to 1/16 inch.

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