Resources Numerical accuracy Calculation policy

3D view drawing

Draws the model in the 3D view: section planes and boxes, the turned section frame, picking and walking.

How the precision is kept

The viewer draws with three.js from 32-bit vertex buffers on the GPU. The calculations listed here place clipping planes and frames for the view; none of them changes a model value.

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.

viewer3d.js BimCraft 0.8.1 32-bit, display only 3 calculations Reviewed

Tests None found by the review

Clipping planes of a section box

32-bit, display only

Turns each section cell's planes into the viewer's clipping planes and draws the cell's frame a hair inside it.

viewer normal = turn(−n_x, −n_z, n_y); frame inset = Σ sizes × 1e-5 + 1e-4

Plane positions are 64-bit until three.js hands them to the GPU. The frame is moved inward by a small fixed amount so it is not clipped by its own planes.

  • viewer3d.js
  • lines 446 to 456
  • BimCraft 0.8.1
const e = (hi.x - lo.x + hi.y - lo.y + hi.z - lo.z) * 1e-5 + 1e-4;
for (const cell of cells) {
  const pl = cellPlanes(cell), g = [];
  for (const q of pl) { g.push(planes.length); planes.push(new THREE.Plane().setFromNormalAndCoplanarPoint(this.turnDir(new THREE.Vector3(-q.n[0], -q.n[2], q.n[1])), P(q.p))); }
  groups.push(g);
  // the cell's edges, a hair inside (every plane clips the model; the frame is drawn unclipped over it)
  const ph = polyhedron(pl);
  if (!ph.verts.length) continue;
  const c = ph.verts.reduce((s, v) => s.add(P(v)), new THREE.Vector3()).multiplyScalar(1 / ph.verts.length);
  const V = ph.verts.map((v) => { const x = P(v), d = c.clone().sub(x); const l = d.length(); return l > e ? x.add(d.multiplyScalar(e / l)) : x; });
  for (const [a, z] of ph.edges) frame.push(V[a], V[z]);

Section frame turned with the building

32-bit, display only

Rotates a viewer point about the vertical through the model's center into the section frame.

x′ = c_x + x cos a + z sin a; z′ = c_z − x sin a + z cos a

A plane rotation in 64-bit, used to place section planes and grips in the view.

  • viewer3d.js
  • lines 591 to 596
  • BimCraft 0.8.1
/** viewer → the section frame (turned by −sectionTurn about the vertical through the box's centre), and back. */
toTurned(p) {
  if (!this.sectionTurn) return p.clone();
  const c = this.box.getCenter(new THREE.Vector3()), a = -this.sectionTurn, x = p.x - c.x, z = p.z - c.z;
  return new THREE.Vector3(c.x + x * Math.cos(a) + z * Math.sin(a), p.y, c.z - x * Math.sin(a) + z * Math.cos(a));
}

Model bounds in the section frame

32-bit, display only

The bounds of every drawn vertex in the turned section frame.

box = min and max of turned vertex positions

Reads the meshes' 32-bit position attribute. The box sets the range of the section sliders in the view.

  • viewer3d.js
  • lines 575 to 590
  • BimCraft 0.8.1
/** The model's bounds in the section frame: the box itself when not turned, else the tight bounds of every vertex. */
secBox() {
  if (!this.sectionTurn) return this.box;
  const key = this.box.min.toArray().concat(this.box.max.toArray()).join() + '|' + this.sectionTurn + '|' + this.meshes.length;
  if (this._secBox && this._secBoxKey === key) return this._secBox;
  const bb = new THREE.Box3(), v = new THREE.Vector3();
  for (const m of [...this.meshes, ...(this.spaceMeshes || [])]) {
    if (!m.visible && !m.parent?.visible) continue;
    m.updateMatrixWorld();
    const pos = m.geometry.getAttribute('position');
    for (let i = 0; i < pos.count; i++) bb.expandByPoint(this.toTurned(v.fromBufferAttribute(pos, i).applyMatrix4(m.matrixWorld)));
  }
  if (bb.isEmpty()) bb.copy(this.box);
  this._secBox = bb; this._secBoxKey = key;
  return bb;
}

In detail

Method
three.js meshes, clipping planes and raycasting.
Number types
Float32Array vertex buffers for the GPU; 64-bit numbers for plane and frame positions.

Approach: Display only

Computed to draw the screen, often in 32-bit on the graphics processor. No number a person reads, saves or exports comes from it.

Every policy that takes this approach