Resources Numerical accuracy Calculation policy

Plan symbol positions

Stores where a plan symbol sits and how it is turned, and moves symbols fixed to a wall when the wall moves.

How the precision is kept

A symbol's point is stored in file units rounded to 6 decimals and its angle in degrees rounded to 4 decimals. A symbol fixed to a wall keeps a distance along the wall and a side, and its point is recomputed on the wall's face in 64-bit millimeters.

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.

plan-symbols.js BimCraft 0.8.1 64-bit 3 calculations Reviewed

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

Stored position and angle

64-bit

The X, Y and Angle written for a symbol.

X, Y = round(mm ÷ unit, 6); Angle = round(radians × 180 ÷ π, 4)

The point is rounded to 6 decimals of the file unit. The angle is converted to degrees and rounded to 4 decimals, and is converted back to radians when read.

  • plan-symbols.js
  • lines 62 to 63
  • BimCraft 0.8.1
['X', 'IFCLENGTHMEASURE', round(w.u(s.at[0]))], ['Y', 'IFCLENGTHMEASURE', round(w.u(s.at[1]))], ['Angle', 'IFCREAL', round((s.angle * 180) / Math.PI, 4)],
...(s.wall ? [['Wall', 'IFCIDENTIFIER', String(s.wall)], ['Side', 'IFCINTEGER', s.side < 0 ? -1 : 1], ['Offset', 'IFCLENGTHMEASURE', round(w.u(num(s.offset)))], ['Base', 'IFCREAL', round(((num(s.base)) * 180) / Math.PI, 4)]] : [])]);

Point on a wall face

64-bit

The point on a wall's face at a distance along the wall, and the direction the face looks.

at = a + s·u + side × (t ÷ 2)·n; face angle = atan2(side·n_y, side·nₓ)

The wall's direction is normalized with Math.hypot. One expression per coordinate; the wall is treated as straight.

  • plan-symbols.js
  • lines 87 to 91
  • BimCraft 0.8.1
/** The spot on a wall face `side` of the wall at distance `s` along it (the same maths as the Electrical devices, res-elec.js). */
function onWall(wl, s, side) {
  const d = [wl.b[0] - wl.a[0], wl.b[1] - wl.a[1]], L = Math.hypot(d[0], d[1]) || 1, u = [d[0] / L, d[1] / L], n = [-u[1], u[0]];
  return { at: [wl.a[0] + u[0] * s + n[0] * side * wl.t / 2, wl.a[1] + u[1] * s + n[1] * side * wl.t / 2], base: Math.atan2(n[1] * side, n[0] * side), L };
}

Symbols following a wall

64-bit

Moves a symbol to where its stored side and distance are on the wall now.

turn = atan2(sin Δ, cos Δ), Δ = new face angle − stored face angle

The stored distance is clamped to the wall's length. A symbol that moved less than 0.5 mm and turned less than 1e-6 rad is left as stored, so differences below those limits are not written.

  • plan-symbols.js
  • lines 92 to 109
  • BimCraft 0.8.1
/** Symbols fixed to a wall follow it: put again where the stored side and offset are now. A wall that is gone leaves the symbol where it was. Returns how many moved. */
export function syncPlanSymbols(w, storey) {
  const list = readPlanSymbols(w).filter((d) => d.storey === storey && d.wall);
  if (!list.length) return 0;
  const walls = readWalls(w, storey);
  let n = 0;
  for (const d of list) {
    const wl = walls.find((x) => x.guid === d.wall);
    if (!wl) continue;
    const g = onWall(wl, Math.min(Math.max(0, d.offset), Math.hypot(wl.b[0] - wl.a[0], wl.b[1] - wl.a[1])), d.side);
    let turn = g.base - d.base;
    turn = Math.atan2(Math.sin(turn), Math.cos(turn));
    if (Math.hypot(g.at[0] - d.at[0], g.at[1] - d.at[1]) < 0.5 && Math.abs(turn) < 1e-6) continue;
    w.upsertPset(d.id, PLAN_SYMBOL_PSET, [['X', 'IFCLENGTHMEASURE', round(w.u(g.at[0]))], ['Y', 'IFCLENGTHMEASURE', round(w.u(g.at[1]))], ['Angle', 'IFCREAL', round(((d.angle + turn) * 180) / Math.PI, 4)], ['Base', 'IFCREAL', round((g.base * 180) / Math.PI, 4)]]);
    n++;
  }
  return n;
}

In detail

Method
Point on a wall face = start + along × unit direction + side × half thickness × normal; turn = new face angle − stored face angle, wrapped with atan2(sin, cos).
Number types
64-bit numbers; stored angles are decimal degrees with 4 decimals.
Tolerances
A symbol is rewritten when it moved 0.5 mm or more or turned 1e-6 rad or more.
Limits
An angle read back from the file is on a 0.0001° grid.

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.

Every policy that takes this approach