Works out the point spacing, the point count and the elevation scaling when an elevation grid or a LiDAR file is brought into a project, and the cell size offered when a surface is written as a GeoTIFF.
How the precision is kept
The dialog works in 64-bit numbers. The scale between file units and project units is measured by converting two nearby points and dividing the distance between them by their spacing. Default spacings and cell sizes are rounded to 6 significant digits before they are shown in the input box; the value in the box is the one used. Coordinates and elevations of imported points are multiplied or converted in 64-bit and are not rounded here.
Calculations under this policy
6 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.
The factor that turns a spacing typed in project units into the file's own units.
k = |f(c + d) − f(c)| ÷ d, c = middle of the file
Two points d apart are converted and the distance between the results is divided by d; d is one cell for a grid and 1/1000 of the file width (at least 1e-6) for LiDAR. The subtraction of two converted coordinates that differ by only d loses digits in proportion to coordinate size ÷ d. The result falls back to 1 when it is not a positive finite number.
gis-terrain-ui.js
lines 269 to 279
CivilCraft 0.8.1
// project units per file unit near the file's middle (for spacings)
function unitScale() {
const f = xf().fn, c = boxOk ? [(fileBox.minX + fileBox.maxX) / 2, (fileBox.minY + fileBox.maxY) / 2] : [0, 0];
const d = kind === 'grid' ? Math.hypot(src.gt[1], src.gt[4]) : Math.max(1e-6, (fileBox.maxX - fileBox.minX) / 1000) || 1;
try {
const a = f(c[0], c[1]), b = f(c[0] + d, c[1]);
const k = Math.hypot(b[0] - a[0], b[1] - a[1]) / d;
if (Number.isFinite(k) && k > 0) return k;
} catch { /* fall through */ }
return 1;
}
Default thinning spacing
64-bit
The spacing the dialog proposes so the import stays under the point limit.
The proposed value is rounded to 6 significant digits with toPrecision(6) before it goes in the input box. It is a setting, not a measurement; the number in the box is what the import uses.
The counts are whole-number arithmetic on columns, rows and the step. The step is round(spacing ÷ cell size) from gridStep (thin.js), where the cell size in project units is hypot of two geotransform terms times the unit scale, a 64-bit value.
Each kept LiDAR point's position and elevation as stored in the project.
(x, y) → f(x, y); z → z × z factor
The elevation is multiplied by the unit factor from zFactor (terrain.js) in one 64-bit multiplication. x and y pass through unchanged when the two coordinate systems are the same, otherwise through the conversion function. Nothing is rounded in this step.
gis-terrain-ui.js
lines 458 to 461
CivilCraft 0.8.1
if (sBox && (x < sBox.minX || x > sBox.maxX || y < sBox.minY || y > sBox.maxY)) { th.seen++; th.outside++; return; }
if (!st.classes.has(c)) { th.seen++; th.filtered++; return; }
if (id) th.add(x, y, z * zf, c);
else { const q = f(x, y); th.add(q[0], q[1], z * zf, c); }
Default GeoTIFF cell size
64-bit
The cell size proposed when a surface is exported as an elevation grid.
cell = average triangle edge ÷ 2.5, rounded to a 1-2-5 step
The proposal is rounded to 6 significant digits with toPrecision(6) and written into the input box; the export passes Number(box value) to surfaceGrid (geotiff-write.js). The cell size is a setting, so the rounding does not change any surveyed value.
The number of columns and rows the dialog says the export will have.
nx = ⌈width ÷ cell⌉ + 1; ny = ⌈height ÷ cell⌉ + 1
Width and height are differences of the surface bounds, multiplied by the local scale factor when the project uses a local system. This is the dialog's estimate; the written grid's size comes from surfaceGrid in geotiff-write.js.
gis-terrain-ui.js
lines 571 to 573
CivilCraft 0.8.1
let w = b.maxX - b.minX, h = b.maxY - b.minY;
if (f && crs.local) w = w * crs.local.scale, h = h * crs.local.scale;
const nx = Math.ceil(w / c) + 1, ny = Math.ceil(h / c) + 1;
In detail
Method
Finite-difference scale at the middle of the file; counts from whole-number grid steps; elevation × unit factor.
Number types
64-bit numbers; whole numbers for counts and steps.
Tolerances
The LiDAR probe distance is 1/1000 of the file width with a floor of 1e-6 file units. Default spacing and default cell size are rounded with toPrecision(6).
Limits
The unit scale is taken at one place (the middle of the file) and used for the whole file. The readers, the thinning and the coordinate conversion live in raster.js, las.js, thin.js, terrain.js, crs.js and geotiff-write.js, which this review of the dialog does not cover.
Approach: 64-bit, direct
Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.