Resources Numerical accuracy Calculation policy

Lengths and units for Library items

Reads lengths written as text (30", 2'-6 1/2", 762 mm) into millimeters and writes sizes back as short labels.

How the precision is kept

Lengths are parsed to millimeters with the defined unit factors (25.4 mm per inch, 304.8 mm per foot). Feet, inches and a fraction are added first and multiplied by 25.4 once. Parsing does not round; pipe sizes and preview labels are rounded to the nearest eighth of an inch or whole millimeter as text.

Open item. Keep a pipe size that is not a whole number of eighths as it was given.

Calculations under this policy

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

libitem.js CadCraft 0.8.2 64-bit 5 calculations Reviewed

Tests bin/test-cadcraft.mjs, bin/test-bimcraft.mjs

Millimeters per unit

Exact

The table of unit factors.

in 25.4; ft 304.8; yd 914.4; mi 1 609 344; mil 0.0254; µm 0.001

The factors are the defined values, none of them rounded. The whole-number factors are exact in binary; 25.4, 304.8, 914.4, 0.0254 and 0.001 are each the nearest 64-bit number to that decimal.

  • libitem.js
  • lines 283 to 284
  • CadCraft 0.8.2
/** Length units → mm. */
export const UNIT_MM = { mm: 1, cm: 10, dm: 100, m: 1000, km: 1e6, in: 25.4, ft: 304.8, yd: 914.4, mi: 1609344, mil: 0.0254, um: 0.001 };

Length from text

64-bit

A typed or stored length in millimeters.

with a unit: n × factor; feet and inches: (feet × 12 + inches + a ÷ b) × 25.4; bare number: n × mm per unit

Feet, whole inches and the fraction are added first and multiplied by 25.4 once at the end. A fraction with a zero denominator gives Infinity, which the callers in this file reject with Number.isFinite. Nothing is rounded here.

  • libitem.js
  • lines 1087 to 1100
  • CadCraft 0.8.2
/** "30", 30" , 2'-6", 2' 6 1/2", 762 mm, 76.2 cm, 0.76 m → mm (bare numbers × mmPerUnit). NaN if not a length. */
export function parseLength(s, mmPerUnit = 1) {
  const t = String(s ?? '').trim().replace(/[\u2032\u2019]/g, "'").replace(/[\u2033\u201d]/g, '"').toLowerCase();
  if (!t) return NaN;
  let m = t.match(/^(-?\d+(?:\.\d+)?)\s*(mm|cm|m|in|ft)$/);
  if (m) return Number(m[1]) * UNIT_MM[m[2]];
  m = t.match(/^(?:(\d+(?:\.\d+)?)\s*'\s*-?\s*)?(?:(\d+(?:\.\d+)?)(?:\s+(\d+)\/(\d+))?|(\d+)\/(\d+))?\s*(?:"|in)?$/);
  if (m && (m[1] || m[2] || m[5]) && /['"]/.test(t)) {
    const ft = Number(m[1] || 0), inch = Number(m[2] || 0) + (m[3] ? Number(m[3]) / Number(m[4]) : 0) + (m[5] ? Number(m[5]) / Number(m[6]) : 0);
    return (ft * 12 + inch) * 25.4;
  }
  if (/^-?\d+(\.\d+)?$/.test(t)) return Number(t) * mmPerUnit;
  return NaN;
}

Drawing units

Exact

The millimeters per drawing unit of a DWG or DXF file.

The file's INSUNITS code picks a factor from the same table. When the file does not say, millimeters or inches is assumed from its MEASUREMENT setting and a note says so.

  • libitem.js
  • lines 1457 to 1468
  • CadCraft 0.8.2
/** Drawing units → mm per unit, the key, and a note when the drawing does not say. */
export function drawingUnits(db, override) {
  if (override) {
    if (!UNIT_MM[override]) throw new Error(msg('libitem.units.unknown', { units: override, list: Object.keys(UNIT_MM).join(', ') }));
    return { key: override, mm: UNIT_MM[override], note: null };
  }
  const key = INSUNITS[db.header?.INSUNITS ?? 0];
  if (key) return { key, mm: UNIT_MM[key], note: null };
  const metric = Number(db.header?.MEASUREMENT) === 1;
  const k = metric ? 'mm' : 'in';
  return { key: k, mm: UNIT_MM[k], note: msg(metric ? 'libitem.units.assumed_mm' : 'libitem.units.assumed_in') };
}

Pipe size in eighths of an inch

64-bit

A decimal inch size written as a fraction, such as 1 1/2".

eighths = round((n − ⌊n⌋) × 8)

The fraction is rounded to the nearest eighth with Math.round and the result is stored as text. A size that is not a whole number of eighths is changed: 0.3125 (5/16) becomes 3/8".

  • libitem.js
  • lines 1078 to 1085
  • CadCraft 0.8.2
function inches(v) {
  const n = Number(v);
  if (!Number.isFinite(n) || n <= 0) return v;
  const whole = Math.floor(n), eighths = Math.round((n - whole) * 8);
  if (eighths === 8) return (whole + 1) + '"';
  const f = eighths ? ['', '1/8', '1/4', '3/8', '1/2', '5/8', '3/4', '7/8'][eighths] : '';
  return (whole ? whole + (f ? ' ' : '') : '') + f + '"';
}

Size label on the preview

64-bit

The overall width and depth printed on an item's preview picture.

millimeters: round(mm); inches: round(mm ÷ 25.4 × 8) eighths

A label only: millimeters rounded to a whole number, inches to the nearest eighth. The item's stored sizes are not changed by it.

  • libitem.js
  • lines 1903 to 1908
  • CadCraft 0.8.2
/** '72"', '25½"' for whole/eighth inches, else mm ('762'). */
export function lengthLabel(mm, inches) {
  if (!inches) return String(Math.round(mm));
  const e = Math.round(mm / 25.4 * 8), whole = Math.floor(e / 8), frac = ['', '⅛', '¼', '⅜', '½', '⅝', '¾', '⅞'][e % 8];
  return (whole > 0 || !frac ? String(whole) : '') + frac + '"';
}

In detail

Method
Regular expressions for a number with a unit, feet and inches with an optional fraction, and a bare number in the drawing's unit.
Number types
64-bit numbers.
Limits
Pipe sizes from plumbing attribute fields are stored as text to the nearest 1/8 inch, so a size of 5/16 is stored as 3/8.

Approach: 64-bit, direct

Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.

Every policy that takes this approach