Placed triangles of an element
32-bit in partEvery 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.
/** 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 };
}