Resources Numerical accuracy Calculation policy

Length tags and tag schedules

Keeps a length tag on an element as an IFC property and lists tag values in schedules, in millimeters.

How the precision is kept

A length tag is read from the file in the file's length unit and shown in millimeters. Each conversion is one 64-bit multiplication followed by rounding to six decimals: six decimals of a millimeter when read, six decimals of the written value when stored. Schedules group rows by the rounded value.

Calculations under this policy

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

tags.js BimCraft 0.8.1 64-bit 3 calculations Reviewed

Tests tools/bimcraft-test/tags-test.mjs

Tag values of an element

64-bit

An element's tags as their kinds keep them, lengths in millimeters.

length in mm = round(value × unitMm × 1e6) ÷ 1e6

One multiplication by the unit factor, then rounding to six decimals of a millimeter. Yes-or-no tags become 1 or 0.

  • tags.js
  • lines 146 to 159
  • BimCraft 0.8.1
/** An element's tag values as their kinds keep them (length in mm); tags with no value are left out. */
export function tagValues(w, id, defs) {
  const ps = w.readPset(id, TAGS_PSET);
  if (!ps) return {};
  const out = {};
  for (const d of defs) {
    if (!(d.name in ps)) continue;
    let v = ps[d.name];
    if (d.kind === 'yesno') v = asBool(v) ? 1 : 0;
    else if (d.kind === 'length' && typeof v === 'number') v = Math.round(v * w.unitMm * 1e6) / 1e6;
    if (v !== null && v !== undefined && v !== '') out[d.name] = v;
  }
  return out;
}

Tag value written to the file

64-bit

A tag as the IFC property that holds it.

stored length = round(u(value) × 1e6) ÷ 1e6

A length goes through the model writer's u() and is rounded to six decimals before it is written. Other kinds are written as given.

  • tags.js
  • line 239
  • BimCraft 0.8.1
const typedRow = (w, def, v) => [def.name, IFC_TYPE[def.kind], def.kind === 'length' ? Math.round(w.u(v) * 1e6) / 1e6 : def.kind === 'yesno' ? !!v : v];

Schedule rows and groups

64-bit

The rows of a tag schedule and the groups they fall in.

length column = round(value × unitMm × 1e6) ÷ 1e6

Length columns and a length group value are multiplied by the unit factor and rounded to six decimals. The group key is the JSON text of that rounded value.

  • tags.js
  • lines 324 to 332
  • BimCraft 0.8.1
const kinds = columns.map((c) => fieldKind(ix, defs, c));
const rr = elementRows(ix, { keys: pick ? [...pick] : null, columns });
for (const r of rr.rows) r.values = r.values.map((v, i) => (kinds[i] === 'length' && typeof v === 'number' ? Math.round(v * unitMm * 1e6) / 1e6 : v));
const groups = new Map();
for (const r of rr.rows) {
  let g = groupBy ? ix.value(groupBy, r.key - ix.keyBase) : null;
  if (groupBy && (g === undefined || g === null)) g = '';
  if (groupBy && fieldKind(ix, defs, groupBy) === 'length' && typeof g === 'number') g = Math.round(g * unitMm * 1e6) / 1e6;
  const k = JSON.stringify(g);

In detail

Method
Read: value × mm per file unit, then Math.round(v × 1e6) ÷ 1e6. Write: the model writer's u(value), rounded the same way.
Number types
64-bit numbers.
Limits
Rows are grouped by the text of the rounded value, so lengths that round to the same six decimals fall in one group.

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