Resources Numerical accuracy Calculation policy

Survey point files: reading and writing

Reads survey points from CSV or text files, counts them by description group, and writes them back as a PNEZD file.

How the precision is kept

Coordinates are converted from text with Number(), which gives the nearest 64-bit value to the decimal typed. The writer rounds northing, easting and elevation to a fixed number of decimals, 3 by default.

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.

points.js CivilCraft 0.8.1 64-bit 3 calculations Reviewed

Tests bin/test-civilcraft.mjs

Coordinates read from a row

64-bit

Takes the northing, easting and elevation of one line of a point file.

The three fields are checked with isNum and converted with Number(), the nearest 64-bit value to the decimal text. An empty elevation is stored as null, not 0. A duplicate point number is refused and counted.

  • points.js
  • lines 84 to 94
  • CivilCraft 0.8.1
const N = c[iN], E = c[iE], Z = c[iZ];
if (!isNum(N) || !isNum(E)) { bad(r, t('pts.bad.ne')); continue; }
if (Z !== undefined && Z !== '' && !isNum(Z)) { bad(r, t('pts.bad.z')); continue; }
if (out.latlon && (Math.abs(Number(N)) > 90 || Math.abs(Number(E)) > 180)) { bad(r, t('pts.bad.latlon')); continue; }
let n = iP >= 0 ? String(c[iP] ?? '').trim() : '';
if (iP >= 0 && !n) { bad(r, t('pts.bad.nonum')); continue; }
if (iP < 0) { do n = String(++auto); while (seen.has(n)); }
if (seen.has(n)) { out.duplicates++; bad(r, t('pts.bad.twice', { num: n })); continue; }
seen.add(n);
const z = Z === undefined || Z === '' ? null : Number(Z);
out.points.push({ n, x: Number(E), y: Number(N), z, d: iD >= 0 ? cleanText(c[iD] ?? '') : '' });

Points written as a PNEZD file

64-bit

Writes point number, northing, easting, elevation and description, comma separated.

N, E and Z written with dec decimals (3 by default)

Each coordinate is written with toFixed(dec). With the default, a coordinate with seven digits before the decimal point is written with 10 significant digits, fewer than the 64-bit value holds.

  • points.js
  • lines 182 to 186
  • CivilCraft 0.8.1
/** A PNEZD comma file of the points (descriptions quoted when they hold a comma or quote). */
export function writePoints(points, dec = 3) {
  const q = (s) => (/[",]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s);
  return points.map((p) => [q(String(p.n)), p.y.toFixed(dec), p.x.toFixed(dec), p.z === null ? '' : p.z.toFixed(dec), q(p.d || '')].join(',')).join('\r\n') + '\r\n';
}

Point count per group

Exact

Counts the points of each description group.

Whole-number counts kept in a Map, one increment per point, then sorted by group name.

  • points.js
  • lines 159 to 163
  • CivilCraft 0.8.1
export function pointGroups(points, keyOf = null) {   // keyOf(point) → group (0.4 V16: description keys); default the first word
  const m = new Map();
  for (const p of points) { const k = keyOf ? keyOf(p) : groupKey(p.d); m.set(k, (m.get(k) || 0) + 1); }
  return [...m].map(([key, count]) => ({ key, count })).sort((a, b) => a.key.localeCompare(b.key));
}

In detail

Method
Rows are split on the detected delimiter and mapped to columns by the format (PNEZD and its variants); numbers are converted with Number().
Number types
64-bit numbers; whole-number counts.
Limits
writePoints writes 3 decimals unless the caller asks for more. Latitude and longitude rows outside ±90° and ±180° are 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