Resources Numerical accuracy Calculation policy

Element triangles for analysis

Hands the placed triangles of an IFC element, in the file's coordinates and length unit, to the daylight, solar, embodied-carbon, library and placement code.

How the precision is kept

The IFC engine (ifc/api.js GetGeometry) hands each shape's vertices over as a Float32Array made by Mesh.interleaved() in ifc/geo-mesh.js, in the shape's own frame before its placement. productTriangles then applies the placement matrix, the optional inverse coordination matrix, the turn from Y up to Z up and the unit factor in 64-bit, and returns plain arrays of 64-bit numbers. Every coordinate it returns therefore starts from a 32-bit value, which holds 24 significant bits (about 7 digits) of the vertex's position within its own shape.

Open item. Read the IFC engine's 64-bit mesh positions (Mesh.pos) in productTriangles instead of the 32-bit interleaved vertex array.

Calculations under this policy

1 calculation 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.

ifc-util.js BimCraft 0.8.1 32-bit in part 1 calculation Reviewed

Tests bin/test-bimcraft.mjs

Placed triangles of an element

32-bit in part

Every triangle of an element in the file's Z-up coordinates and length unit.

p = (x, −z, y) of (C⁻¹ · M · v) × (1000 ÷ unitMm)

v is a Float32Array from the IFC engine (ifc/api.js GetGeometry returns Mesh.interleaved() of ifc/geo-mesh.js), so each vertex has 24 significant bits before any arithmetic here. The matrix products and the unit factor are 64-bit and the result is pushed to a plain Array, so nothing further is lost. The factor 1000 ÷ unitMm is a rounded quotient for inch and foot files.

  • ifc-util.js
  • lines 157 to 180
  • BimCraft 0.8.1
/** Every placed triangle of a product, in the file's Z-up coordinates and length unit. Ci = inverse coordination matrix
 * when the model was opened with COORDINATE_TO_ORIGIN (undoes the shift). */
export function productTriangles(api, mid, id, unitMm, Ci = null) {
  const fm = api.GetFlatMesh(mid, id);
  const pos = [], idx = [];
  const toUnit = 1000 / unitMm;   // web-ifc meters → file units
  for (let g = 0; g < fm.geometries.size(); g++) {
    const pg = fm.geometries.get(g);
    const geom = api.GetGeometry(mid, pg.geometryExpressID);
    const v = api.GetVertexArray(geom.GetVertexData(), geom.GetVertexDataSize());
    const ix = api.GetIndexArray(geom.GetIndexData(), geom.GetIndexDataSize());
    const m = pg.flatTransformation, base = pos.length / 3;
    for (let i = 0; i < v.length; i += 6) {
      let [x, y, z] = apply4(m, v[i], v[i + 1], v[i + 2]);
      if (Ci) [x, y, z] = apply4(Ci, x, y, z);
      const [X, Y, Z] = yupToZup(x, y, z);
      pos.push(X * toUnit, Y * toUnit, Z * toUnit);
    }
    for (let i = 0; i < ix.length; i++) idx.push(base + ix[i]);
    geom.delete();
  }
  if (fm.delete) fm.delete();
  return { positions: pos, indices: idx };
}

In detail

Method
For each piece of the element: vertex → flatTransformation (meters, Y up) → inverse coordination matrix when given → (x, −z, y) → × 1000 ÷ unitMm.
Number types
In: Float32Array vertices (x y z nx ny nz), Uint32Array indices, a 16-number matrix of 64-bit numbers. Out: positions as a plain Array of 64-bit numbers, indices as a plain Array of integers.
Limits
The 32-bit step comes before the placement, so the loss is relative to the size of the coordinates in the shape's own frame; a shape defined directly in site coordinates loses correspondingly more. The normals in the vertex array are not used. In this release daylight-bim.js, pv-calc.js, carbon-calc.js, libitem-ifc.js and ifc-place.js import this function.

Approach: 32-bit step, flagged

One step stores or exchanges 32-bit values that reach a number a person reads. It is listed here with its open item, and the step is either moved to 64-bit or the app will warn where the number is read.

Every policy that takes this approach