The points, directions, placements and level elevations written when a model is exported as an IFC4 file.
How the precision is kept
Geometry is computed in 64-bit and every real number is written with 9 decimals. For coordinates in meters that is 1 nanometer, but for the unit direction vectors of a placement it is 9 significant digits. Points whose 9-decimal text is equal are written once.
Open item. Write placement directions with 15 or more significant digits instead of 9 decimals.
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.
How every coordinate, direction component and elevation is written.
text = x rounded to 9 decimals
toFixed(9) rounds to 1e-9 in absolute terms: 1 nanometer for a coordinate in meters, 9 digits for a component of a unit direction. A rounded value that prints in exponent form is written instead from the unrounded number with 10 significant digits.
m3d/io.js
line 1813
CadCraft 0.8.2
const real = (x) => { let v = +(+x).toFixed(9); if (Object.is(v, -0) || Math.abs(v) < 1e-12) v = 0; let s = String(v); if (s.includes('e')) s = (+x).toExponential(9).replace('e', 'E'); if (!/[.E]/.test(s)) s += '.'; return s; };
Shared points
64-bit
The corner points of the faces, each written once.
Two corners become one IfcCartesianPoint when their coordinates agree as text at 9 decimals.
m3d/io.js
line 1865
CadCraft 0.8.2
const P = (p) => { const k2 = p.map((x) => (+x).toFixed(9)).join(','); if (!pts.has(k2)) pts.set(k2, pt(p)); return pts.get(k2); };
Is a placement rigid
64-bit
Decides whether a group is exported in its own coordinates with a placement, or in world coordinates.
A placement with any scale, mirror or skew beyond these tolerances is not written as an IFC placement; its geometry is multiplied out to world coordinates instead.
m3d/io.js
lines 1815 to 1823
CadCraft 0.8.2
function rigid(m) {
const cols = [[m[0], m[1], m[2]], [m[4], m[5], m[6]], [m[8], m[9], m[10]]];
if (Math.abs(m[3]) + Math.abs(m[7]) + Math.abs(m[11]) > 1e-12 || Math.abs(m[15] - 1) > 1e-12) return false;
for (let a = 0; a < 3; a++) {
if (Math.abs(len(cols[a]) - 1) > 1e-9) return false;
for (let b = a + 1; b < 3; b++) if (Math.abs(dot(cols[a], cols[b])) > 1e-9) return false;
}
return det3(m) > 0;
}
Placement of an element
64-bit
Where each exported element sits relative to its level.
location = (t_x, t_y, t_z − level elevation); axis = third column; ref direction = first column
The location is the matrix translation with the level's elevation subtracted from z. The axis and reference direction are the normalized third and first columns, each written to 9 decimals, so the rotation in the file carries 9 digits.
m3d/io.js
lines 1875 to 1877
CadCraft 0.8.2
// placed relative to its storey, so it stays where it is in the world
const axes = m ? L(`IFCAXIS2PLACEMENT3D(${pt([m[12], m[13], m[14] - lv.elevation])},${dir(norm([m[8], m[9], m[10]]))},${dir(norm([m[0], m[1], m[2]]))})`)
: lv.elevation ? L(`IFCAXIS2PLACEMENT3D(${pt([0, 0, -lv.elevation])},$,$)`) : null;
Level of an element
64-bit
Which level an element is listed under.
the highest level with elevation ≤ z_min + 1e-6
z_min is the lowest corner of the element in world coordinates; the comparison has an absolute slack of 1e-6 m.
m3d/io.js
lines 1854 to 1855
CadCraft 0.8.2
/** The storey an element whose lowest point is z belongs to: the highest one at or below it (the lowest if none). */
const levelOf = (z) => { let s = levels[0]; for (const l of levels) if (l.elevation <= z + 1e-6) s = l; return s; };
Precision stated in the file
64-bit
The precision value the IFC file declares for its geometry.
The geometric representation context is written with a fixed precision of 1.E-05, while coordinates are written to 9 decimals.
One faceted shape per top-level group or component, in the group's own coordinates when its placement is rigid (placed by an IfcAxis2Placement3D), otherwise in world coordinates.
Number types
64-bit numbers, written with toFixed(9).
Tolerances
Rigid placement: column lengths within 1e-9 of 1, columns square within 1e-9, bottom row within 1e-12. Level of an element: elevation ≤ lowest point + 1e-6 m. The file's geometric context states a precision of 1e-5.
Limits
A placement's axis directions are rounded to 9 decimals, so a point D meters from the placement's origin can shift by an amount on the order of D × 1e-9 m when the file is read. The precision stated in the file (1e-5) is coarser than the 1e-9 the coordinates are written to.
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.