Resources Numerical accuracy Calculation policy

Ground read from a survey file

Reads ground points from a points file, drawing contours, a LAS or LAZ cloud, an elevation grid or LandXML, and sets their unit, offset and datum before they become the site's ground.

How the precision is kept

Points files, contours and LandXML are read as 64-bit numbers. A LAS or LAZ cloud is read through the point cloud loader, which keeps positions as 32-bit offsets from a whole-unit origin; the ground points are those offsets added back to the origin. An elevation grid is thinned to about 15000 points. One unit factor is applied to x, y and z.

Open item. Take the ground points of a LAS or LAZ file from 64-bit coordinates instead of the loader's 32-bit display offsets.

Calculations under this policy

4 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.

res-ui.js BimCraft 0.8.1 32-bit in part 4 calculations Reviewed

Tests None found by the review

Millimeters per survey unit

Exact

The factor from a survey file's length unit to millimeters.

m = 1000; ft = 304.8; US survey ft = 1200 ÷ 3937 × 1000

The foot is the exact 304.8 mm and the US survey foot is written as its defining fraction, 1200 ÷ 3937 m, evaluated in 64-bit.

  • res-ui.js
  • line 664
  • BimCraft 0.8.1
const UNIT_MM = { mm: 1, m: 1000, ft: 304.8, ftUS: 1200 / 3937 * 1000 };

Ground points from a LAS or LAZ cloud

32-bit in part

Takes the ground-class points of a cloud and thins them to the lowest point in each 1 m cell.

x = pos[3i] + origin_x; cell = 1000 ÷ (mm per unit)

cloud.pos is the Float32Array of offsets that pointcloud.js keeps for drawing, so each coordinate has been stored in 32-bit before the origin is added back in 64-bit. These points become the site's ground. Points are kept only when classified as ground (class 2) if the file has that class.

  • res-ui.js
  • lines 694 to 699
  • BimCraft 0.8.1
const cloud = await PC.loadCloud(f, info, { budget: 400000 });
const pts = [];
for (let i = 0; i < cloud.n; i++) { if (cloud.cls && cloud.classCounts?.get(2) && cloud.cls[i] !== 2) continue; pts.push({ x: cloud.pos[3 * i] + cloud.origin[0], y: cloud.pos[3 * i + 1] + cloud.origin[1], z: cloud.pos[3 * i + 2] + cloud.origin[2] }); }
const unit = cloud.unit || R.tr.unit;
const cell = 1000 / UNIT_MM[unit];   // 1 m cells, the lowest point in each (ground)
return { points: thinToGrid(pts, cell), lines: [], unit, zUnit: cloud.zUnit || unit, crs: info.crs || null };

Thinning an elevation grid

64-bit

Chooses every how many cells of a GeoTIFF or ASCII grid to read so that about 15000 points remain.

step = max(1, ⌈√(width × height ÷ 15000)⌉)

A whole-number step in both directions. The ground then comes from that subset of the grid's cells, so detail finer than the step is not in the surface.

  • res-ui.js
  • line 704
  • BimCraft 0.8.1
const step = Math.max(1, Math.ceil(Math.sqrt(src.width * src.height / 15000)));

Unit, offset and datum of an imported ground

64-bit

Sets the unit factor, moves far-off coordinates to the building and picks the datum so the ground near the building sits 200 mm under the first floor.

datum = median(z near the building) + 200 ÷ k

The median is the middle element of the sorted elevations within 10000 mm of the building's center, or of all points when none are near. The same factor k is applied to x, y and z; the separate vertical unit that readGroundFile returns is not read here. A unit name missing from the table gets a factor of 1.

  • res-ui.js
  • lines 771 to 777
  • BimCraft 0.8.1
const k = UNIT_MM[r.unit] || 1;
const offset = autoOffset(all, k, buildingCentre());
// the datum: the ground near the building sits 8" under the first floor
const c = buildingCentre(), near = all.filter((p) => Math.hypot(p.x * k - offset[0] - c[0], p.y * k - offset[1] - c[1]) < 10000).map((p) => p.z).sort((a, b) => a - b);
const zs = near.length ? near : all.map((p) => p.z).sort((a, b) => a - b);
const datum = zs[Math.floor(zs.length / 2)] + 200 / k;
const pts = toModel(r.points, { unitMm: k, offset, datum }), lines = r.lines.map((l) => toModel(l, { unitMm: k, offset, datum }));

In detail

Method
Unit factor in millimeters per source unit; offset from the middle of the points to the building; datum = the median elevation near the building plus 200 mm.
Number types
64-bit numbers, except LAS and LAZ positions, which are a Float32Array of offsets from the cloud's origin (pointcloud.js). The US survey foot is 1200 ÷ 3937 m.
Tolerances
Points within 10000 mm of the building's center set the datum; all points when none are that near.
Limits
A cloud is thinned to the lowest point in each 1 m cell and loaded with a budget of 400000 points. An unknown unit name is read with a factor of 1.

Approach: 32-bit step, flagged

One step stores or exchanges 32-bit values that reach a number a person reads. It is listed here with its open item, and the step is either moved to 64-bit or the app will warn where the number is read.

Every policy that takes this approach