Resources Numerical accuracy Calculation policy

LAS and LAZ point coordinates

Reads a LiDAR file's header and turns each stored point into x, y, z in the file's coordinates.

How the precision is kept

The LAS format stores each coordinate as a signed 32-bit integer with a 64-bit scale and offset per axis in the header. The reader multiplies and adds in 64-bit arithmetic and rounds nothing, so the coordinates are as fine as the file's own scale. Counts and offsets are whole numbers held in 64-bit numbers.

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.

las.js CadCraft 0.8.2 64-bit 4 calculations Reviewed

Tests bin/test-pointcloud.mjs, bin/test-civilcraft-terrain.mjs

Point coordinates

64-bit

The x, y and z of one point record.

x = X × scaleₓ + offsetₓ (and the same for y and z)

X, Y and Z are read as signed 32-bit integers, which a 64-bit number holds exactly. Each is multiplied by the header's 64-bit scale and added to its 64-bit offset: two rounded operations per coordinate, nothing else.

  • las.js
  • lines 158 to 165
  • CadCraft 0.8.2
function decoder(h) {
  const [sx, sy, sz] = h.scale, [ox, oy, oz] = h.offset, ext = h.format >= 6;
  return (dv, o, onPoint) => {
    const x = dv.getInt32(o, true) * sx + ox, y = dv.getInt32(o + 4, true) * sy + oy, z = dv.getInt32(o + 8, true) * sz + oz;
    const cls = ext ? dv.getUint8(o + 16) : dv.getUint8(o + 15) & 31;
    onPoint(x, y, z, cls);
  };
}

Scale, offset and bounds from the header

64-bit

Reads the header's scale, offset, minimum and maximum and refuses a scale that cannot be used.

All twelve values are read as 64-bit doubles and kept as read. A scale of 0, a scale larger than 1e6 in size, or any scale or offset that is not finite stops the import.

  • las.js
  • lines 57 to 61
  • CadCraft 0.8.2
const scale = [dv.getFloat64(131, true), dv.getFloat64(139, true), dv.getFloat64(147, true)];
const offset = [dv.getFloat64(155, true), dv.getFloat64(163, true), dv.getFloat64(171, true)];
const max = [dv.getFloat64(179, true), dv.getFloat64(195, true), dv.getFloat64(211, true)];
const min = [dv.getFloat64(187, true), dv.getFloat64(203, true), dv.getFloat64(219, true)];
if (![...scale, ...offset].every(Number.isFinite) || scale.some((s) => s === 0 || Math.abs(s) > 1e6)) throw bad('las.bad.scale');

64-bit counts and offsets

64-bit

Reads an unsigned 64-bit integer (LAS 1.4 point count, extended record positions and lengths).

value = hi × 2³² + lo

Built from two unsigned 32-bit halves in a 64-bit number. The result is exact up to 2⁵³; a larger value would lose its low bits.

  • las.js
  • line 38
  • CadCraft 0.8.2
const u64 = (dv, o) => { const lo = dv.getUint32(o, true), hi = dv.getUint32(o + 4, true); return hi * 4294967296 + lo; };

Points the file really holds

Exact

The number of whole point records between the first point and the end of the point data.

available = ⌊(end − offset to points) ÷ record length⌋, at most the header's count

Whole numbers divided and rounded down. When the result is below the header's count, the smaller number is used and a note says so; for a compressed file the header's count is kept.

  • las.js
  • lines 97 to 101
  • CadCraft 0.8.2
let available = count;
if (!compressed) {
  available = Math.floor((end - offsetToPoints) / recordLength);
  if (available < count) notes.push(t('las.short', { available: available.toLocaleString('en-US'), count: count.toLocaleString('en-US') }));
  else available = count;

In detail

Method
coordinate = stored integer × scale + offset, per axis (LAS 1.0 to 1.4; LAZ points are decoded by the laz-perf library and then read the same way).
Number types
Signed 32-bit integers from the file; 64-bit scale, offset and results.
Limits
The file's scale sets the resolution. A 64-bit count or offset above 2⁵³ would lose its low bits. A scale of 0, above 1e6 in size or not finite is refused.

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