Resources Numerical accuracy Calculation policy

Field layout points from the model

Works out the points a crew sets out from the model (column feet, wall axis ends, anchor bolts, sleeves, chosen elements) in model or survey coordinates, in meters, millimeters or feet.

How the precision is kept

A point is the IFC placement matrix (64-bit, file units) applied to a local point and multiplied by the millimeters per file unit. Conversion to the unit asked multiplies by the reciprocal 1 ÷ 1000 or 1 ÷ 304.8 instead of dividing, which adds one rounding. Nothing is rounded in this file.

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.

layout-bim.js BimCraft 0.8.1 64-bit 3 calculations Reviewed

Tests bin/test-layout.mjs

Placed point in millimeters

64-bit

A point of an element's own frame in the file's coordinates, in millimeters.

p = (M · (x, y, z, 1)) × unitMm

Three products and the translation summed in order, then one multiplication by the unit factor, all 64-bit. For a model far from the origin the translation dominates the sum and sets the size of the rounding.

  • layout-bim.js
  • line 35
  • BimCraft 0.8.1
const at = (m, p) => [m[0] * p[0] + m[4] * p[1] + m[8] * p[2] + m[12], m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13], m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]].map((v) => v * unitMm);

Wall axis ends

64-bit

The two ends of a wall's axis as field points.

The first and last points of the axis curve are read from the file with Number() and placed with the wall's matrix; their height is set to 0 in the wall's own frame.

  • layout-bim.js
  • lines 59 to 64
  • BimCraft 0.8.1
if (Array.isArray(cv?.Points)) pts = cv.Points.map((h) => (line(h.value)?.Coordinates || []).map((c) => Number(val(c))));   // IfcPolyline
else if (cv?.Points?.value) pts = (line(cv.Points.value)?.CoordList || []).map((p) => p.map((c) => Number(val(c))));   // IfcIndexedPolyCurve
if (!pts || pts.length < 2) continue;
const a = [pts[0][0], pts[0][1], 0], b = [pts[pts.length - 1][0], pts[pts.length - 1][1], 0];
push('wall', id, l, at(m, a));
push('wall', id, l, at(m, b));

Points in the unit and coordinates asked

64-bit

The field points in meters, millimeters or feet, in model or survey coordinates.

k = 1 ÷ (mm per unit); model: x × k; survey: E × 1000 × k

The scale is the reciprocal of 1000, 1 or 304.8, computed once and multiplied in, so a coordinate in feet is x × (1 ÷ 304.8) and can differ from x ÷ 304.8 in the last digit. Survey coordinates divide by the file's unit factor first and go through fileToMap in meters.

  • layout-bim.js
  • lines 94 to 104
  • BimCraft 0.8.1
/** The points in the units and coordinates asked (file mm in, Z up). */
export function inUnits(points, { coords = 'model', georef = null, unitMm = 1, unit = 'm' } = {}) {
  const k = 1 / (UNIT_MM[unit] || 1000);
  return points.map((p) => {
    if (coords === 'survey' && georef?.kind === 'map') {
      const [E, N, H] = fileToMap(georef, [p.x / unitMm, p.y / unitMm, p.z / unitMm]);
      return { ...p, x: E * 1000 * k, y: N * 1000 * k, z: H * 1000 * k };
    }
    return { ...p, x: p.x * k, y: p.y * k, z: p.z * k };
  });
}

In detail

Method
World point = M · p × unitMm, with M from GetWorldTransformMatrix. Survey coordinates go through fileToMap (ifc-geo.js) in meters and are then scaled to the unit asked.
Number types
64-bit numbers.
Limits
Wall ends are the first and last point of the wall's Axis representation at local height 0; a wall without an Axis representation gives no points.

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