Reads spot levels written as text or block attributes into points with a height, and checks a surveyor's drawing for unit, origin, flat-contour, outlier and duplicate problems.
How the precision is kept
A level is taken from its written digits with one conversion, then x, y and z are multiplied once by the unit scale. The check is a set of rules with fixed thresholds: sizes in meters, outliers by the median and the median absolute deviation, duplicates by 1 mm cells. Its results are counts and warnings, not measurements.
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.
Reads a level such as 104.37, +104,37 or EL 104.37 from a text.
value = Number(whole digits . decimal digits) × sign
The digits are joined as text and converted once, so the level is the nearest 64-bit number to what is written; a comma is read as the decimal mark. Up to 7 digits before and 6 after the mark are accepted, and without a prefix word the number needs a decimal part.
survey.js
lines 46 to 57
CadCraft 0.8.2
/** A level written as text, or null. */
export function levelFromText(raw, { minDecimals = 1 } = {}) {
const s = plainText(raw);
if (!s || s.length > 40) return null;
const re = new RegExp('^(?:(' + PREFIX + ')\\s*[.:=]?\\s*)?([+\\-−]?)\\s*(\\d{1,7})(?:[.,](\\d{1,6}))?\\s*(?:m|ft|\'|’)?$', 'i');
const m = re.exec(s);
if (!m) return null;
const dec = m[4] || '';
if (!m[1] && dec.length < minDecimals) return null;
const v = Number(m[3] + (dec ? '.' + dec : '')) * (m[2] === '-' || m[2] === '−' ? -1 : 1);
return fin(v) ? v : null;
}
Levels into project units
64-bit
A level point's x, y and z in project units.
x·k, y·k, z·k
Each coordinate is multiplied once by the unit scale k; a scale that is not a positive finite number is replaced by 1. The level takes the text's insertion or alignment point as its position.
How far the data spans and how far it lies from zero, in meters.
span = |(maxX − minX, maxY − minY)| × m per unit; far = max |coordinate| × m per unit
A project in feet is converted with 1200 ÷ 3937 m, the US survey foot, whichever foot it uses; against the international foot that is 2 parts per million in the reported extent. Minimum and maximum are plain comparisons.
survey.js
lines 136 to 146
CadCraft 0.8.2
const mPer = METRES[projectUnit === 'm' ? 'm' : 'ft'];
const code = header?.INSUNITS | 0;
const pts = points.filter((p) => p && fin(p.x) && fin(p.y)).slice(0, MAX_POINTS);
// extent (project units) from the linework and the points
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity, maxAbs = 0, nv = 0;
const grow = (x, y) => { if (!fin(x) || !fin(y)) return; nv++; if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; maxAbs = Math.max(maxAbs, Math.abs(x), Math.abs(y)); };
eachVertex(layers, grow);
for (const p of pts) grow(p.x, p.y);
const spanM = nv > 1 ? Math.hypot(maxX - minX, maxY - minY) * mPer : 0;
const farM = maxAbs * mPer;
Median
64-bit
The middle value of a list of levels.
odd count: the middle value; even: mean of the two middle values
The list is sorted numerically; an even count takes one addition and one halving.
survey.js
line 115
CadCraft 0.8.2
const median = (a) => { const s = [...a].sort((x, y) => x - y), n = s.length; return n % 2 ? s[(n - 1) / 2] : (s[n / 2 - 1] + s[n / 2]) / 2; };
Level outliers
64-bit
Counts levels that are far from the rest, and levels of exactly 0 that look like missing heights.
1.4826 is the usual scale factor for the median absolute deviation, written to five digits. The rule needs at least 8 levels; with fewer, only levels above 9000 m or below −11 000 m are counted. The median and limits in the message are rounded to 2 decimals.
survey.js
lines 181 to 185
CadCraft 0.8.2
if (zs.length >= 8) {
const med = median(zs), mad = median(zs.map((z) => Math.abs(z - med))) * 1.4826;
const lim = Math.max(6 * mad, 5 / mPer);
const zero = Math.abs(med) * mPer > 5 ? zs.filter((z) => z === 0).length : 0;
const out = zs.filter((z) => z !== 0 && (absurd(z) || Math.abs(z - med) > lim)).length;
Duplicate points
64-bit
Counts points that sit on top of another point, with the same or a different level.
cell = 1 mm; key = (round(x ÷ cell), round(y ÷ cell)); same level when |Δz| ≤ cell
Points are binned into 1 mm cells by rounding, so two points closer than 1 mm on either side of a cell edge get different keys and are not counted. Each later point is compared with the first point of its cell only.
survey.js
lines 194 to 200
CadCraft 0.8.2
const cell = 1e-3 / mPer, seen = new Map();
let dup = 0, conflict = 0;
for (const p of pts) {
const key = Math.round(p.x / cell) + ',' + Math.round(p.y / cell);
const prev = seen.get(key);
if (prev === undefined) { seen.set(key, fin(p.z) ? p.z : null); continue; }
if (prev === null || !fin(p.z) || Math.abs(prev - p.z) <= cell) dup++; else conflict++;
In detail
Method
Median and scaled median absolute deviation for outliers; grid binning for duplicates; bounding box for extent.
Number types
64-bit numbers.
Tolerances
Outlier when |z − median| > max(6 × 1.4826 × MAD, 5 m), or outside −11 000 m to 9000 m. Duplicate cells 1 mm; same level within one cell size. Span warnings above 200 km and below 0.5 m; far from the origin above 100 km. Unit scale counts as 1 within 1e-9.
Limits
Feet are taken as 1200 ÷ 3937 m for every project in feet. Two points under 1 mm apart across a cell edge are not counted as duplicates. 1.4826 is a rounded constant.
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.